home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Pascal / Applications / NIH Image 1.62b11 / src / File1.p < prev    next >
Text File  |  1997-05-06  |  100KB  |  3,559 lines

  1. unit File1;
  2.  
  3. {Routines used by NIH Image for implementing File Menu commands.}
  4.  
  5. interface
  6.  
  7.  
  8.     uses
  9.         Types, Memory, QuickDraw, QuickDrawText, Packages, Menus, Events, Fonts, 
  10.         Scrap, ToolUtils, Resources, Errors, Palettes, StandardFile, Windows,
  11.         Controls, TextEdit, Files, Dialogs, TextUtils, Finder, MixedMode, SegLoad,
  12.         globals, Utilities, Graphics, file2, Dicom, sound, Lut, Text, Processes;
  13.  
  14.     function CloseAWindow (WhichWindow: WindowPtr): integer;
  15.     procedure DoClose;
  16.     function OpenFile (fname: str255; vnum: integer): boolean;
  17.     function OpenPict (fname: str255; vnum: integer; Reverting: boolean): boolean;
  18.     procedure SaveFile;
  19.     function DoOpen (FileName: str255; RefNum: integer): boolean;
  20.     function ImportFile (FileName: str255; RefNum: integer): boolean;
  21.     procedure RevertToSaved;
  22.     procedure SaveAs (name: str255; RefNum: integer);
  23.     procedure Export (name: str255; RefNum: integer);
  24.     procedure FindWhatToPrint;
  25.     procedure UpdateFileMenu;
  26.     procedure SaveAsText (fname: str255; RefNum: integer);
  27.     procedure SaveAll;
  28.     function OpenPICS (name: str255; fRefNum: integer): boolean;
  29.     procedure RescaleToEightBits;
  30.  
  31.  
  32. implementation
  33.  
  34.     var
  35.         OpenAllFiles, UseExistingLUT, PICTReadErr: boolean;
  36.         SaveRefNum: integer;
  37.         TempStackInfo: StackInfoRec;
  38.         PictSrcRect: rect;
  39.  
  40. {$PUSH}
  41. {$D-}
  42.  
  43.     procedure LookForCluts (fname: str255; vnum: integer);
  44.         var
  45.             RefNum: integer;
  46.             err: OSErr;
  47.             ok1, ok2: boolean;
  48.     begin
  49.         if not UseExistingLUT then begin
  50.                 err := SetVol(nil, vnum);
  51.                 refNum := OpenResFile(fname);
  52.                 if RefNum <> -1 then begin
  53.                         ok1 := LoadCLUTResource(KlutzID);
  54.                         if not ok1 then
  55.                             ok2 := LoadCLUTResource(PixelPaintID);
  56.                         CloseResFile(refNum);
  57.                     end;
  58.             end;
  59.     end;
  60.  
  61.  
  62.  
  63.     function OpenImageHeader (f: integer; fname: str255; vnum: integer): boolean;
  64.         var
  65.             ByteCount: LongInt;
  66.             err: OSErr;
  67.             TempHdr: PicHeader;
  68.             i, OldNExtra, p1x, p2x: integer;
  69.             ok: boolean;
  70.             hUnitsKind: UnitsType;
  71.     begin
  72.         if SizeOf(PicHeader)<>HeaderSize then begin
  73.             PutError(StringOf('Internal error (size= ', SizeOf(PicHeader):1,')'));
  74.             OpenImageHeader := false;
  75.             exit(OpenImageHeader);
  76.         end;
  77.         ByteCount := HeaderSize;
  78.         err := SetFPos(f, fsFromStart, info^.HeaderOffset);
  79.         err := fsread(f, ByteCount, @TempHdr);
  80.         if CheckIO(err) <> NoErr then begin
  81.                 OpenImageHeader := false;
  82.                 exit(OpenImageHeader);
  83.             end;
  84.         with info^, TempHdr do begin
  85.                 if PictureType <> TiffFile then begin
  86.                         nlines := hnlines;
  87.                         PixelsPerLine := hPixelsPerLine;
  88.                     end;
  89.                 if (hversion > 54) and not UseExistingLUT then begin
  90.                         OldNExtra := nExtraColors;
  91.                         nExtraColors := hnExtraColors;
  92.                         ExtraColors := hExtraColors;
  93.                         if (nExtraColors > 0) or (OldNExtra <> nExtraColors) then
  94.                             RedrawLUTWindow;
  95.                     end;
  96.                 if (hversion >= 42) and not UseExistingLUT then begin
  97.                         if hversion < 142 then begin
  98.                                 LUTMode := hOldLUTMode;
  99.                                 if (LutMode = OldAppleDefault) or (LutMode = OldSpectrum) then
  100.                                     LutMode := ColorLut;
  101.                             end
  102.                         else begin
  103.                                 LUTMode := hLUTMode;
  104.                                 if LutMode = Pseudocolor then begin
  105.                                         if ((hnColors > 32) and (hTable = CustomTable)) or (hTable > spectrum) then
  106.                                             LutMode := ColorLut;
  107.                                     end;
  108.                             end;
  109.                         case LUTMode of
  110.                             PseudoColor: 
  111.                                 if hversion < 142 then begin
  112.                                         nColors := hOldnColors;
  113.                                         for i := 0 to ncolors - 1 do begin
  114.                                                 RedLUT[i] := hr[i];
  115.                                                 GreenLUT[i] := hg[i];
  116.                                                 BlueLUT[i] := hb[i];
  117.                                             end;
  118.                                         ColorEnd := 255 - hOldColorStart;
  119.                                         ColorStart := ColorEnd - nColors * hColorWidth + 1;
  120.                                         if ColorStart < 0 then
  121.                                             ColorStart := 0;
  122.                                         InvertPalette;
  123.                                         FillColor1 := BlackRGB;
  124.                                         FillColor2 := BlackRGB;
  125.                                         ColorTable := CustomTable;
  126.                                         UpdateLUT;
  127.                                     end
  128.                                 else begin {V1.42 or later}
  129.                                         if (hTable <> CustomTable) and (hTable <= spectrum) then begin
  130.                                                 SwitchColorTables(GetColorTableItem(hTable), false);
  131.                                                 if hInvertedTable then
  132.                                                     InvertPalette;
  133.                                             end
  134.                                         else begin
  135.                                                 nColors := hnColors;
  136.                                                 ColorTable := CustomTable;
  137.                                                 if nColors <= 32 then
  138.                                                     for i := 0 to ncolors - 1 do begin
  139.                                                             RedLUT[i] := hr[i];
  140.                                                             GreenLUT[i] := hg[i];
  141.                                                             BlueLUT[i] := hb[i];
  142.                                                         end;
  143.                                             end;
  144.                                         ColorStart := hColorStart;
  145.                                         ColorEnd := hColorEnd;
  146.                                         FillColor1 := hFill1;
  147.                                         FillColor2 := hFill2;
  148.                                         UpdateLUT;
  149.                                         UpdateMap;
  150.                                     end; {v1.42 or later}
  151.                             GrayScale: 
  152.                                 ResetGrayMap;
  153.                             ColorLut, CustomGrayscale: 
  154.                                 if PictureType <> PictFile then begin
  155.                                         if ColorMapOffset > 0 then
  156.                                             GetTiffColorMap(f)
  157.                                         else
  158.                                             LookForCluts(fname, vnum);
  159.                                     end;
  160.                             otherwise
  161.                         end; {case}
  162.                         if hLutMode = CustomGrayscale then
  163.                             LutMode := CustomGrayscale;
  164.                     end;{if}
  165.                 if (hversion >= 65) and ((ForegroundIndex <> hForegroundIndex) or (BackgroundIndex <> hBackgroundIndex)) then begin
  166.                         SetForegroundColor(hForegroundIndex);
  167.                         SetBackgroundColor(hBackgroundIndex);
  168.                     end;
  169.                 if (hversion > 88) and (LUTMode = GrayScale) and not UseExistingLUT then begin
  170.                         if hversion < 138 then begin
  171.                                 p1x := 255 - hp2x;
  172.                                 p2x := 255 - hp1x;
  173.                             end
  174.                         else begin
  175.                                 p1x := hp1x;
  176.                                 p2x := hp2x
  177.                             end;
  178.                         nColors := 256;
  179.                         ColorStart := p1x;
  180.                         ColorEnd := p2x;
  181.                         UpdateLUT;
  182.                     end;
  183.                 if hversion > 106 then begin
  184.                         {xScale := hXScale;} {68k-bug}
  185.                         xScale := DoubleToReal(hXScale);
  186.                         yScale := xScale;
  187.                         PixelAspectRatio := 1.0;
  188.                         SpatiallyCalibrated := xScale <> 0.0;
  189.                     end;
  190.                 if hversion > 140 then begin
  191.                         PixelAspectRatio := hPixelAspectRatio;
  192.                         yScale := xScale / PixelAspectRatio;
  193.                     end;
  194.                 if hversion > 153 then
  195.                     xUnit := hXUnit
  196.                 else begin
  197.                         hUnitsKind := UnitsType(hUnitsID - 5);
  198.                         GetXUnits(hUnitsKind);
  199.                     end;
  200.                 if xUnit = 'pixel' then
  201.                     SpatiallyCalibrated := false;
  202.                 if ((hnCoefficients > 0) and (hfit < Uncalibrated)) or (hfit = UncalibratedOD) then begin
  203.                         if hfit = SpareFit1 then begin
  204.                                 fit := uncalibrated;
  205.                                 DrawLabels('', '', '');
  206.                             end
  207.                         else begin
  208.                                 fit := hfit;
  209.                                 if hfit <> UncalibratedOD then begin
  210.                                         nCoefficients := hnCoefficients;
  211.                                         for i:=1 to maxCoeff do
  212.                                             {Coefficient[i] := hCoeff[i];} {68k-bug}
  213.                                             Coefficient[i]:=DoubleToReal(hCoeff[i]);
  214.                                         nKnownValues := 0;
  215.                                     end;
  216.                                 UnitOfMeasure := hUM;
  217.                                 if hversion >= 144 then
  218.                                     ZeroClip := hZeroClip
  219.                                 else
  220.                                     ZeroClip := false;
  221.                             end;
  222.                     end
  223.                 else begin
  224.                         fit := uncalibrated;
  225.                         DrawLabels('', '', '');
  226.                     end;
  227.                 BinaryPic := hBinaryPic;
  228.                 if hSliceEnd > 1 then begin
  229.                         SliceStart := hSliceStart;
  230.                         SliceEnd := hSliceEnd;
  231.                         if SliceEnd > 254 then
  232.                             SliceEnd := 254;
  233.                     end;
  234.                 if hNSlices > 1 then begin
  235.                         with TempStackInfo do begin
  236.                             nSlices := hNSlices;
  237.                             if nSlices > MaxSlices then
  238.                                 nSlices := MaxSlices;
  239.                             CurrentSlice := hCurrentSlice;
  240.                             if (hCurrentSlice < 1) or (hCurrentSlice > nSlices) then
  241.                                 CurrentSlice := 1;
  242.                             SliceSpacing := hSliceSpacing;
  243.                             FrameInterval := hFrameInterval;
  244.                             StackType := VolumeStack;
  245.                             if hVersion >= 158 then
  246.                                 StackType := hStackType;
  247.                         end;
  248.                     end;
  249.                 FileVersion := hVersion;
  250.                 OpenImageHeader := true
  251.             end;
  252.     end;
  253.  
  254.  
  255.     function OpenHeader (f: integer; fname: str255; vnum: integer; var TiffInfo: TiffInfoRec): boolean;
  256.         var
  257.             ByteCount, FileSize, DirOffset, MaxImages: LongInt;
  258.             hdr: packed array[1..512] of byte;
  259.             err: OSErr;
  260.             TempHdr: PicHeader;
  261.     begin
  262.         with info^ do begin
  263.                 if (WhatToOpen = OpenUnknown) or (WhatToOpen = OpenImported) then begin
  264.                         err := SetFPos(f, fsFromStart, 0);
  265.                         ByteCount := 8;
  266.                         err := fsread(f, ByteCount, @hdr);
  267.                         if ((hdr[1] = 73) and (hdr[2] = 73)) or ((hdr[1] = 77) and (hdr[2] = 77)) then
  268.                             WhatToOpen := OpenTIFF
  269.                         else if WhatToOpen = OpenUnknown then
  270.                             WhatToOpen := OpenImage
  271.                         else
  272.                             WhatToOpen := OpenMCID;
  273.                     end;
  274.                 StackInfo := nil;
  275.                 with TempStackInfo do begin
  276.                         nSlices := 0;
  277.                         CurrentSlice := 1;
  278.                         SliceSpacing := 0.0;
  279.                         FrameInterval := 0.0;
  280.                     end;
  281.                 fileVersion := 0;
  282.                 case WhatToOpen of
  283.                     OpenImage:  begin
  284.                             err := SetFPos(f, fsFromStart, 0);
  285.                             ByteCount := 8;
  286.                             err := fsread(f, ByteCount, @TempHdr);
  287.                             if TempHdr.FileID = FileID8 then begin
  288.                                     HeaderOffset := 0;
  289.                                     PictureType := normal
  290.                                 end
  291.                             else begin
  292.                                     HeaderOffset := -1;
  293.                                     BlockMove(@TempHdr, @hdr, 8);
  294.                                     nlines := hdr[1] + hdr[2] * 256;
  295.                                     PixelsPerLine := hdr[3] + hdr[4] * 256;
  296.                                     PictureType := Imported;
  297.                                     InvertedImage := true;
  298.                                 end;
  299.                             ImageDataOffset := 512;
  300.                         end;
  301.                     OpenMCID:  begin
  302.                             err := SetFPos(f, fsFromStart, 0);
  303.                             ByteCount := 4;
  304.                             err := fsread(f, ByteCount, @hdr);
  305.                             PixelsPerLine := hdr[1] + hdr[2] * 256 + 1;
  306.                             if PixelsPerLine > MaxLine then begin
  307.                                     beep;
  308.                                     PixelsPerLine := MaxLine;
  309.                                 end;
  310.                             nlines := hdr[3] + hdr[4] * 256 + 1;
  311.                             PictureType := imported;
  312.                             LUTMode := grayscale;
  313.                             HeaderOffset := -1;
  314.                             ImageDataOffset := 4;
  315.                         end;
  316.                     OpenCustom:  begin
  317.                             err := GetEof(f, FileSize);
  318.                             if macro then begin
  319.                                     if (ImportCustomOffset + ImportCustomWidth * ImportCustomHeight) > FileSize then begin
  320.                                             AbortMacro;
  321.                                             OpenHeader := false;
  322.                                             exit(OpenHeader)
  323.                                         end;
  324.                                 end;
  325.                             PixelsPerLine := ImportCustomWidth;
  326.                             nlines := ImportCustomHeight;
  327.                             PictureType := imported;
  328.                             HeaderOffset := -1;
  329.                             ImageDataOffset := ImportCustomOffset;
  330.                             if ImportCustomSlices > 1 then
  331.                                 with TempStackInfo do begin
  332.                                         nSlices := ImportCustomSlices;
  333.                                         MaxImages := (FileSize - ImportCustomOffset) div (ImportCustomWidth * ImportCustomHeight);
  334.                                         if nSlices > MaxImages then
  335.                                             nSlices := MaxImages;
  336.                                         if nSlices < 2 then
  337.                                             nSlices := 0;
  338.                                     end;
  339.                         end;
  340.                     OpenPICT2:  begin
  341.                             err := SetFPos(f, fsFromStart, 0);
  342.                             ByteCount := 8;
  343.                             err := fsread(f, ByteCount, @TempHdr);
  344.                             if TempHdr.FileID = FileID8 then
  345.                                 HeaderOffset := 0
  346.                             else
  347.                                 HeaderOffset := -1;
  348.                             PictureType := PictFile;
  349.                             if not UseExistingLUT then
  350.                                 LutMode := ColorLut;
  351.                             ImageDataOffset := 512;
  352.                         end;
  353.                     OpenTIFF:  begin
  354.                             if not OpenTiffHeader(f, DirOffset) then begin
  355.                                     OpenHeader := false;
  356.                                     exit(OpenHeader)
  357.                                 end;
  358.                             if not OpenTiffDirectory(f, DirOffset, TiffInfo, false) then begin
  359.                                     OpenHeader := false;
  360.                                     exit(OpenHeader)
  361.                                 end;
  362.                             with TiffInfo do begin
  363.                                     PictureType := TiffFile;
  364.                                     PixelsPerLine := width;
  365.                                     nlines := height;
  366.                                     if BitsPerPixel = 4 then
  367.                                         PictureType := FourBitTiff;
  368.                                     ImageDataOffset := OffsetToData;
  369.                                     InvertedImage := ZeroIsBlack and (PictureType <> FourBitTIFF);
  370.                                     if resolution > 0.0 then begin
  371.                                             case ResUnits of
  372.                                                 tNoUnits: 
  373.                                                     xUnit := 'pixel';
  374.                                                 tCentimeters: 
  375.                                                     xUnit := 'cm';
  376.                                                 tInches: 
  377.                                                     xUnit := 'inch';
  378.                                             end;
  379.                                             xScale := resolution;
  380.                                             yScale := resolution;
  381.                                             PixelAspectRatio := 1.0;
  382.                                             if xUnit <> 'pixel' then
  383.                                                 SpatiallyCalibrated := true;
  384.                                         end;
  385.                                     ColorMapOffset := OffsetToColorMap;
  386.                                     HeaderOffset := OffsetToImageHeader;
  387.                                 end;
  388.                             if not UseExistingLUT then
  389.                                 LutMode := Grayscale;
  390.                         end;
  391.                 end; {case}
  392.                 if HeaderOffset <> -1 then begin
  393.                         if not OpenImageHeader(f, fname, vnum) then begin
  394.                                 OpenHeader := false;
  395.                                 exit(OpenHeader)
  396.                             end
  397.                     end
  398.                 else if (ColorMapOffset > 0) and not UseExistingLUT then
  399.                     GetTiffColorMap(f);
  400.             end; {with}
  401.         OpenHeader := true;
  402.     end;
  403.  
  404.  
  405.  
  406.     function SaveHeader (f, slines, sPixelsPerLine, vnum: integer; fname: str255; SavingSelection, SavingTIFF: boolean): OSErr;
  407.         var
  408.             TempHdr: PicHeader;
  409.             DummyHdr: array[1..128] of LongInt;
  410.             i: integer;
  411.             ByteCount: LongInt;
  412.             position: LongInt;
  413.             err: OSErr;
  414.             str: str255;
  415.             UnitsKind: UnitsType;
  416.             UnitsPerCM: extended;
  417.     begin
  418.         with TempHdr, info^ do begin
  419.                 for i := 1 to 128 do
  420.                     DummyHdr[i] := 0;
  421.                 BlockMove(@DummyHdr, @TempHdr, HeaderSize);
  422.                 FileID := FileID8;
  423.                 hnlines := nlines;
  424.                 hPixelsPerLine := PixelsPerLine;
  425.                 hversion := version;
  426.                 hLUTMode := LUTMode;
  427.                 hOldLutMode := LutMode;
  428.                 hnColors := ncolors;
  429.                 hOldnColors := 0;
  430.                 if LutMode = Pseudocolor then begin
  431.                         hOldLutMode := ColorLut;
  432.                         if (ColorTable = CustomTable) and (ncolors <= 32) then
  433.                             for i := 0 to nColors - 1 do begin
  434.                                     hr[i] := RedLUT[i];
  435.                                     hg[i] := GreenLUT[i];
  436.                                     hb[i] := BlueLUT[i];
  437.                                 end;
  438.                     end;
  439.                 hColorStart := ColorStart;
  440.                 hColorEnd := ColorEnd;
  441.                 hFill1 := FillColor1;
  442.                 hFill2 := FillColor2;
  443.                 hTable := ColorTable;
  444.                 hInvertedTable := InvertedColorTable;
  445.                 hOldColorStart := 255 - ColorEnd;
  446.                 if nColors > 0 then
  447.                     hColorWidth := (ColorEnd - ColorStart) div nColors
  448.                 else
  449.                     hColorWidth := 1;
  450.                 hnExtraColors := nExtraColors;
  451.                 hExtraColors := ExtraColors;
  452.                 hForegroundIndex := ForegroundIndex;
  453.                 hBackgroundIndex := BackgroundIndex;
  454.                 {hXScale := xScale;} {68k-bug}
  455.                 RealToDouble(xScale, hXScale);
  456.                 hScaleMagnification := 1.0;
  457.                 hPixelAspectRatio := PixelAspectRatio;
  458.                 hUnitsID := 14; {Pixels. For backward compatibility only since hUnits no longer used.}
  459.                 if SpatiallyCalibrated then begin
  460.                         GetUnitsKind(UnitsKind, UnitsPerCM);
  461.                         hUnitsID := ord(UnitsKind) + 5;
  462.                         if hUnitsID > 14 then
  463.                             hUnitsID := 14;
  464.                     end;
  465.                 FindPoints(hp1x, hp1y, hp2x, hp2y);
  466.                 if fit = uncalibrated then
  467.                     hnCoefficients := 0
  468.                 else
  469.                     hnCoefficients := nCoefficients;
  470.                 hfit := fit;
  471.                 for i:=1 to maxCoeff do
  472.                     {hCoeff[i] := Coefficient[i];} {68k-bug}
  473.                     RealToDouble(Coefficient[i], hCoeff[i]);
  474.                 hZeroClip := ZeroClip;
  475.                 hUM := UnitOfMeasure;
  476.                 hBinaryPic := BinaryPic;
  477.                 hSliceStart := SliceStart;
  478.                 hSliceEnd := SliceEnd;
  479.                 if StackInfo <> nil then
  480.                     with StackInfo^ do begin
  481.                             hNSlices := nSlices;
  482.                             hSliceSpacing := SliceSpacing;
  483.                             hFrameInterval := FrameInterval;
  484.                             hCurrentSlice := CurrentSlice;
  485.                             hStackType := StackType;
  486.                         end
  487.                 else begin
  488.                         hNSlices := 0;
  489.                         hSliceSpacing := 0.0;
  490.                         hFrameInterval := 0.0;
  491.                         hCurrentSlice := 0;
  492.                         hStackType := VolumeStack;
  493.                     end;
  494.                 hXUnit := xUnit;
  495.                 ByteCount := SizeOf(TempHdr);
  496.                 if ByteCount <> HeaderSize then begin
  497.                         NumToString(ByteCount, str);
  498.                         PutError('Internal error check: header size is incorrect.');
  499.                         ExitToShell;
  500.                     end;
  501.                 if SavingSelection then begin
  502.                         hnlines := slines;
  503.                         hPixelsPerLine := sPixelsPerLine;
  504.                     end;
  505.                 err := fswrite(f, ByteCount, @TempHdr);
  506.                 SaveHeader := CheckIO(err);
  507.             end; {with}
  508.     end;
  509.  
  510.  
  511.     procedure PackLines;
  512.   {For odd width images, removes the extra bytes at the end of each line required to make RowBytes even.}
  513.         var
  514.             i: integer;
  515.             SrcPtr, DstPtr: ptr;
  516.     begin
  517.         with info^ do begin
  518.                 SrcPtr := ptr(ord4(PicBaseAddr) + BytesPerRow);
  519.                 DstPtr := ptr(ord4(PicBaseAddr) + PixelsPerLine);
  520.                 for i := 1 to nlines - 1 do begin
  521.                         BlockMove(SrcPtr, DstPtr, PixelsPerLine);
  522.                         SrcPtr := ptr(ord4(SrcPtr) + BytesPerRow);
  523.                         DstPtr := ptr(ord4(DstPtr) + PixelsPerLine);
  524.                     end;
  525.             end;
  526.     end;
  527.  
  528.  
  529.     procedure UnpackLines;
  530.   {For odd width images, adds an extra byte to each line so RowBytes is even.}
  531.         var
  532.             i: integer;
  533.             SrcPtr, DstPtr: ptr;
  534.     begin
  535.         with info^ do begin
  536.                 SrcPtr := ptr(ord4(PicBaseAddr) + (nlines - 1) * PixelsPerLine);
  537.                 DstPtr := ptr(ord4(PicBaseAddr) + (nlines - 1) * BytesPerRow);
  538.                 for i := 1 to nlines - 1 do begin
  539.                         BlockMove(SrcPtr, DstPtr, PixelsPerLine);
  540.                         SrcPtr := ptr(ord4(SrcPtr) - PixelsPerLine);
  541.                         DstPtr := ptr(ord4(DstPtr) - BytesPerRow);
  542.                     end;
  543.             end;
  544.     end;
  545.  
  546.  
  547.     function WriteSlices (f: integer): integer;
  548.         var
  549.             ByteCount, SelectionSize: LongInt;
  550.             i, err, SaveCS: integer;
  551.     begin
  552.         with info^, Info^.StackInfo^ do begin
  553.                 SaveCS := CurrentSlice;
  554.                 for i := 1 to nSlices do begin
  555.                         CurrentSlice := i;
  556.                         SelectSlice(CurrentSlice);
  557.                         UpdateTitleBar;
  558.                         ByteCount := ImageSize;
  559.                         if odd(PixelsPerLine) then
  560.                             PackLines;
  561.                         err := fswrite(f, ByteCount, PicBaseAddr);
  562.                         if odd(PixelsPerLine) then
  563.                             UnpackLines;
  564.                         if err <> 0 then
  565.                             leave;
  566.                     end;
  567.                 CurrentSlice := SaveCS;
  568.                 SelectSlice(CurrentSlice);
  569.                 UpdateTitleBar;
  570.                 WriteSlices := err;
  571.             end;
  572.     end;
  573.  
  574.  
  575.     procedure WriteSelection (f: integer; sLines, sPixelsPerLine: LongInt);
  576.   {Contributed by Edward J. Huff(huff@mcclb0.med.nyu.edu).}
  577.         var
  578.             size, offset, ByteCount, BytesDone: LongInt;
  579.             src, dst: ptr;
  580.             err: OSErr;
  581.     begin
  582.         if sPixelsPerLine > UndoBufSize then
  583.             exit(WriteSelection);
  584.         size := sLines * sPixelsPerLine;
  585.         with info^, info^.RoiRect do begin
  586.                 offset := top * BytesPerRow + left;
  587.                 src := ptr(ord4(PicBaseAddr) + offset);
  588.                 BytesDone := 0;
  589.                 while BytesDone < size do begin
  590.                         ByteCount := 0;
  591.                         dst := UndoBuf;
  592.                         while ((ByteCount + sPixelsPerLine) < UndoBufSize) and (BytesDone < size) do begin
  593.                                 BlockMove(src, dst, sPixelsPerLine);
  594.                                 src := ptr(ord4(src) + BytesPerRow);
  595.                                 dst := ptr(ord4(dst) + sPixelsPerLine);
  596.                                 ByteCount := ByteCount + sPixelsPerLine;
  597.                                 BytesDone := BytesDone + sPixelsPerLine;
  598.                             end;
  599.                         err := fswrite(f, ByteCount, UndoBuf);
  600.                     end;
  601.                 SetupUndo; {Needed for drawing roi outline}
  602.             end
  603.     end;
  604.  
  605.  
  606.     procedure SaveRGBTiff(f: integer; SavingSelection: boolean);
  607.     const
  608.         bufsize = 12000;
  609.     var
  610.         i, row, pixel, count, ignore: LongInt;
  611.         vstart, height, hstart, width: LongInt;
  612.         buffer: packed array [0 .. bufsize] of byte;
  613.         rLine, gLine, bLine: LineType;
  614.         err: OSErr;
  615.     begin
  616.         with info^ do begin
  617.             if SavingSelection then with RoiRect do begin
  618.                 vstart := top;
  619.                 height := bottom - top;
  620.                 hstart := left;
  621.                 width := right - left;
  622.             end else begin
  623.                 vstart := 0;
  624.                 height := nLInes;
  625.                 hstart := 0;
  626.                 width := PixelsPerLine;
  627.             end;
  628.             if width > MaxLine then
  629.                 exit(SaveRGBTiff);
  630.             ShowMeter;
  631.             count := 0;
  632.             for row:=0 to height - 1 do begin
  633.                 if (row mod 10) = 0 then
  634.                     UpdateMeter(((row * 100) div height), 'Saving RGB TIFF');
  635.                 SelectSlice(1);
  636.                 GetLine(hstart, vstart + row, width, rLine);
  637.                 SelectSlice(2);
  638.                 GetLine(hstart, vstart + row, width, gLine);
  639.                 SelectSlice(3);
  640.                 GetLine(hstart, vstart + row, width, bLine);
  641.                 for pixel := 0 to width - 1 do begin
  642.                     buffer[count] := 255 - rLine[pixel];
  643.                     buffer[count + 1] := 255 - gLine[pixel];
  644.                     buffer[count + 2] := 255 - bLine[pixel];
  645.                     count := count + 3;
  646.                     if count > (bufsize - 3) then begin
  647.                         if CheckIO(fswrite(f, count, @buffer)) <> noErr then begin
  648.                             exit(SaveRGBTiff);
  649.                             UpdateMeter(-1, '');
  650.                         end;
  651.                         count := 0;
  652.                     end;
  653.                 end; {for}
  654.             end; {for}
  655.             if count > 0 then
  656.                 err := fswrite(f, count, @buffer);
  657.             UpdateMeter(-1, '');
  658.             with StackInfo^ do begin
  659.                 CurrentSlice := 1;
  660.                 SelectSlice(CurrentSlice);
  661.             end;
  662.             UpdateTitleBar;
  663.         end; {with}
  664.     end;
  665.     
  666.  
  667.     function SaveTiffFile (fname: str255; vnum: integer; slines, sPixelsPerLine: integer; SavingSelection: boolean): boolean;
  668.         var
  669.             f, err, i, width, height: integer;
  670.             HdrSize, ByteCount, ctabSize, StackTiffDirSize, ImageDataSize: LongInt;
  671.             TheInfo: FInfo;
  672.             MCIDHeader: packed array[1..4] of byte;
  673.             SaveColorMap, SaveAs24BitTiff: boolean;
  674.     begin
  675.         SaveTiffFile := false;
  676.         SaveAs24BitTiff := false;
  677.         ShowWatch;
  678.         err := fsopen(fname, vNum, f);
  679.         if CheckIO(err) <> 0 then
  680.             exit(SaveTiffFile);
  681.         with Info^ do begin
  682.                 SaveColorMap := (LutMode <> Grayscale) and (SaveAsWhat <> asRawData);
  683.                 if SaveAsWhat = SaveAsMCID then begin
  684.                         if SavingSelection then begin
  685.                                 width := sPixelsPerLine;
  686.                                 height := slines;
  687.                             end
  688.                         else begin
  689.                                 width := PixelsPerLine;
  690.                                 height := nLines;
  691.                             end;
  692.                         MCIDHeader[1] := (width - 1) mod 256;
  693.                         MCIDHeader[2] := (width - 1) div 256;
  694.                         MCIDHeader[3] := (height - 1) mod 256;
  695.                         MCIDHeader[4] := (height - 1) div 256;
  696.                         ByteCount := 4;
  697.                         err := fswrite(f, ByteCount, @MCIDHeader);
  698.                     end;
  699.                 HeaderOffset := TiffDirSize;
  700.                 ImageDataOffset := TiffDirSize + HeaderSize;
  701.                 if SaveColorMap then
  702.                     ctabSize := SizeOf(TiffColorMapType)
  703.                 else
  704.                     ctabSize := 0;
  705.                 StackTiffDirSize := 0;
  706.                 if SavingSelection then
  707.                     ImageDataSize := ord4(sLines) * sPixelsPerLine
  708.                 else
  709.                     ImageDataSize := ImageSize;
  710.                 if StackInfo <> nil then begin
  711.                         ImageDataSize := ImageSize * StackInfo^.nSlices;
  712.                         if SaveAsWhat <> asRawData then
  713.                             StackTiffDirSize := SizeOf(StackIFDType) * (StackInfo^.nSlices - 1);
  714.                         if (StackInfo^.StackType = rgbStack) and (StackInfo^.nSlices = 3) then begin
  715.                             SaveAs24BitTiff := true;
  716.                             ctabSize := 0;
  717.                             StackTiffDirSize := 0;
  718.                         end;
  719.                     end;
  720.                 if (SaveAsWhat <> asRawData) and (SaveAsWhat <> SaveAsMCID) then begin
  721.                         if SaveTiffDir(f, slines, sPixelsPerLine, SavingSelection, ctabSize, ImageDataSize) <> NoErr then begin
  722.                                 err := fsclose(f);
  723.                                 err := FSDelete(fname, vnum);
  724.                                 exit(SaveTiffFile)
  725.                             end;
  726.                         err := SetFPos(f, FSFromStart, TiffDirSize);
  727.                         if SaveHeader(f, slines, sPixelsPerLine, vnum, fname, SavingSelection, true) <> NoErr then begin
  728.                                 err := fsclose(f);
  729.                                 err := FSDelete(fname, vnum);
  730.                                 exit(SaveTiffFile)
  731.                             end;
  732.                     end;
  733.                 if SaveAsWhat = SaveAsMCID then
  734.                     KillRoi;
  735.                 if SaveAs24bitTiff then
  736.                     SaveRGBTiff(f, SavingSelection)
  737.                 else if SavingSelection then
  738.                     WriteSelection(f, sLines, sPixelsPerLine)
  739.                 else if StackInfo <> nil then
  740.                     err := WriteSlices(f)
  741.                 else begin
  742.                         ByteCount := ImageDataSize;
  743.                         if odd(PixelsPerLine) then
  744.                             PackLines;
  745.                         err := fswrite(f, ByteCount, PicBaseAddr);
  746.                         if odd(PixelsPerLine) then
  747.                             UnpackLines;
  748.                     end;
  749.                 if SaveAsWhat = SaveAsMCID then
  750.                     InvertPic;
  751.                 if CheckIO(err) <> 0 then begin
  752.                         err := fsclose(f);
  753.                         err := FSDelete(fname, vnum);
  754.                         exit(SaveTiffFile)
  755.                     end;
  756.                 if SaveAsWhat = asRawData then
  757.                     HdrSize := 0
  758.                 else if SaveAsWhat = SaveAsMCID then begin
  759.                         HdrSize := 4;
  760.                         SaveAsWhat := asRawData;
  761.                     end
  762.                 else
  763.                     HdrSize := HeaderSize + TiffDirSize;
  764.                 if SaveColorMap then
  765.                     SaveTiffColorMap(f, ImageDataSize);
  766.                 if StackTiffDirSize > 0 then
  767.                     err := WriteExtraTiffIFDs(f, ImageDataSize, cTabSize);
  768.                 err := SetEOF(f, HdrSize + ImageDataSize + ctabSize + StackTiffDirSize);
  769.                 err := fsclose(f);
  770.                 err := GetFInfo(fname, vnum, TheInfo);
  771.                 if TheInfo.fdCreator <> 'Imag' then begin
  772.                         TheInfo.fdCreator := 'Imag';
  773.                         err := SetFInfo(fname, vnum, TheInfo);
  774.                     end;
  775.                 if SaveAsWhat = asRawData then begin
  776.                         TheInfo.fdType := 'RawD';
  777.                         err := SetFInfo(fname, vnum, TheInfo);
  778.                     end
  779.                 else if TheInfo.fdType <> 'TIFF' then begin
  780.                         TheInfo.fdType := 'TIFF';
  781.                         err := SetFInfo(fname, vnum, TheInfo);
  782.                     end;
  783.                 err := FlushVol(nil, vNum);
  784.                 if not SavingSelection then begin
  785.                         if (PictureType <> BlankField) and (PictureType <> FrameGrabberType)  and (SaveAsWhat <> asRawData) then begin
  786.                                 PictureType := TiffFile;
  787.                                 RemovePath(fname);
  788.                                 TruncateString(fname, maxTitle);
  789.                                 title := fname;
  790.                                 vref := vnum;
  791.                                 UpdateTitleBar;
  792.                                 if StackInfo = nil then begin
  793.                                         revertable := true;
  794.                                         InvertedImage := false;
  795.                                     end;
  796.                             end;
  797.                     end;
  798.                 if (SaveAsWhat <> asRawData) and (not RoiShowing) then
  799.                     Changes := false;
  800.             end; {with}
  801.         SaveTiffFile := true;
  802.     end;
  803.  
  804.  
  805.     procedure SaveAsTIFF (fname: str255; RefNum: integer; slines, sPixelsPerLine: integer; SavingSelection: boolean);
  806.         var
  807.             err: integer;
  808.             TheInfo: FInfo;
  809.             replacing, ok: boolean;
  810.             name: str255;
  811.     begin
  812.         if info = NoInfo then
  813.             exit(SaveAsTIFF);
  814.         err := GetFInfo(fname, RefNum, TheInfo);
  815.         case err of
  816.             NoErr: 
  817.                 with TheInfo do begin
  818.                         if (fdType <> 'TIFF') and (fdType <> 'PICT') and (fdType <> 'IPIC') and (fdType <> 'RawD') and (fdType <> 'PICS') then begin
  819.                                 TypeMismatch(fname);
  820.                                 exit(SaveAsTIFF)
  821.                             end;
  822.                         replacing := true;
  823.                     end;
  824.             FNFerr:  begin
  825.                     if SaveAsWhat = asRawData then
  826.                         err := create(fname, RefNum, 'Imag', 'RawD')
  827.                     else
  828.                         err := create(fname, RefNum, 'Imag', 'TIFF');
  829.                     if CheckIO(err) <> 0 then
  830.                         exit(SaveAsTIFF);
  831.                     replacing := false;
  832.                 end;
  833.             otherwise
  834.                 if CheckIO(err) <> 0 then
  835.                     exit(SaveAsTIFF);
  836.         end;
  837.         if replacing then
  838.             if not RoomForFile(fname, RefNum, slines, sPixelsPerLine, SavingSelection) then
  839.                 exit(SaveAsTIFF);
  840.         ok := SaveTiffFile(fname, RefNum, slines, sPixelsPerLine, SavingSelection);
  841.         if ok then
  842.             UpdateWindowsMenuItem;
  843.         with info^ do
  844.             if SavingSelection and Replacing and (PictureType <> BlankField) and (PictureType <> FrameGrabberType)  then
  845.                 PictureType := Leftover;
  846.     end;
  847.  
  848.  
  849.     function SavePICTFile (fname: str255; vnum: integer; SavingSelection, NewFile: boolean): boolean;
  850.         var
  851.             f, err, i, v: integer;
  852.             ByteCount, PICTSize: LongInt;
  853.             PicH: PicHandle;
  854.             fRect, frect2: rect;
  855.             tPort: GrafPtr;
  856.             TheInfo: FInfo;
  857.             SaveInfoRec: PicInfo;
  858.             HeaderSaved: boolean;
  859.             SaveGDevice: GDHandle;
  860.  
  861.         procedure Abort;
  862.         begin
  863.             err := fsclose(f);
  864.             if NewFile then
  865.                 err := FSDelete(fname, vnum);
  866.             DisposeHandle(handle(PicH));
  867.             {exit(SavePICTFile)}   {ppc-bug}
  868.         end;
  869.  
  870.     begin
  871.         with info^ do begin
  872.                 if OpPending then
  873.                     KillRoi;
  874.                 SavePICTFile := false;
  875.                 ShowWatch;
  876.                 GetPort(tPort);
  877.                 if SavingSelection then
  878.                     fRect := RoiRect
  879.                 else
  880.                     SetRect(fRect, 0, 0, PixelsPerLine, nlines);
  881.                 with frect do
  882.                     SetRect(frect2, 0, 0, right - left, bottom - top);
  883.                 with osPort^ do begin
  884.                         SaveGDevice := GetGDevice;
  885.                         SetGDevice(osGDevice);
  886.                         SetPort(GrafPtr(osPort));
  887.                         pmForeColor(BlackIndex);
  888.                         pmBackColor(WhiteIndex);
  889.                         if OldSystem then begin
  890.                                 RGBForeColor(BlackRGB);
  891.                                 RGBBackColor(WhiteRGB);
  892.                             end;
  893.                         ClipRect(PicRect);
  894.                         LoadLUT(cTable);
  895.                         PicH := OpenPicture(fRect2);
  896.                         CopyBits(BitMapHandle(PortPixMap)^^, BitMapHandle(PortPixMap)^^, frect, frect2, SrcCopy, nil);
  897.                         ClosePicture;
  898.                         pmForeColor(ForegroundIndex);
  899.                         pmBackColor(BackgroundIndex);
  900.                     end;
  901.                 SetPort(tPort);
  902.                 SetGDevice(SaveGDevice);
  903.                 PICTSize := GetHandleSize(handle(PicH));
  904.                 if PICTSize <= 10 then begin
  905.                         PutError('Sorry, but there is not enough memory available to save this PICT file. Try closing some windows, or save as TIFF.');
  906.                         if NewFile then
  907.                             err := FSDelete(fname, vnum);
  908.                         DisposeHandle(handle(PicH));
  909.                         exit(SavePICTFile)
  910.                     end;
  911.                 err := fsopen(fname, vnum, f);
  912.                 err := SetFPos(f, FSFromStart, 0);
  913.                 SaveInfoRec := Info^;
  914.                 if (LutMode = GrayScale) or (LutMode = CustomGrayScale) then begin
  915.                         nColors := 256;
  916.                         ColorStart := 0;
  917.                         ColorEnd := 255;
  918.                         LUTMode := Grayscale;
  919.                         IdentityFunction := true;
  920.                     end;
  921.                 HeaderSaved := SaveHeader(f, 0, 0, vnum, fname, SavingSelection, false) = 0;
  922.                 Info^ := SaveInfoRec;
  923.                 if not HeaderSaved then begin
  924.                     abort;
  925.                     exit(SavePICTFile)
  926.                 end;
  927.                 err := fswrite(f, PICTSize, pointer(PicH^));
  928.                 if CheckIO(err) <> 0 then begin
  929.                     abort; 
  930.                     exit(SavePICTFile)
  931.                 end;
  932.                 DisposeHandle(handle(PicH));
  933.                 ByteCount := PICTSize + HeaderSize;
  934.                 err := SetEOF(f, ByteCount);
  935.                 err := fsclose(f);
  936.                 err := GetFInfo(fname, vnum, TheInfo);
  937.                 if TheInfo.fdCreator <> 'Imag' then begin
  938.                         TheInfo.fdCreator := 'Imag';
  939.                         err := SetFInfo(fname, vnum, TheInfo);
  940.                     end;
  941.                 if TheInfo.fdType <> 'PICT' then begin
  942.                         TheInfo.fdType := 'PICT';
  943.                         err := SetFInfo(fname, vnum, TheInfo);
  944.                     end;
  945.                 err := FlushVol(nil, vnum);
  946.                 if not SavingSelection then begin
  947.                         if (PictureType <> BlankField) and (PictureType <> FrameGrabberType)  and (PictureType <> NullPicture) then begin
  948.                                 PictureType := PictFile;
  949.                                 RemovePath(fname);
  950.                                 TruncateString(fname, maxTitle);
  951.                                 title := fname;
  952.                                 UpdateTitleBar;
  953.                                 vref := vnum;
  954.                                 revertable := true;
  955.                                 InvertedImage := false;
  956.                             end;
  957.                         Changes := false;
  958.                     end;
  959.             end; {with}
  960.         SavePICTFile := true;
  961.     end;
  962.  
  963.  
  964.     procedure SaveAsPICT (fname: str255; RefNum: integer; SavingSelection: boolean);
  965.         var
  966.             f, err, i: integer;
  967.             where: Point;
  968.             TheInfo: FInfo;
  969.             replacing, ok: boolean;
  970.             name: str255;
  971.     begin
  972.         err := GetFInfo(fname, RefNum, TheInfo);
  973.         case err of
  974.             NoErr: 
  975.                 with TheInfo do begin
  976.                         if (fdType <> 'TIFF') and (fdType <> 'PICT') and (fdType <> 'IPIC') then begin
  977.                                 TypeMismatch(fname);
  978.                                 exit(SaveAsPICT)
  979.                             end;
  980.                         replacing := true;
  981.                     end;
  982.             FNFerr:  begin
  983.                     err := create(fname, RefNum, 'Imag', 'PICT');
  984.                     if CheckIO(err) <> 0 then
  985.                         exit(SaveAsPICT);
  986.                     replacing := false;
  987.                 end;
  988.             otherwise
  989.                 if CheckIO(err) <> 0 then
  990.                     exit(SaveAsPICT);
  991.         end;
  992.         ok := SavePICTFile(fname, RefNum, SavingSelection, not Replacing);
  993.         if ok then
  994.             UpdateWindowsMenuItem;
  995.         with info^ do
  996.             if SavingSelection and replacing and (PictureType <> BlankField) and (PictureType <> FrameGrabberType)  then
  997.                 PictureType := Leftover;
  998.     end;
  999.  
  1000.  
  1001.     procedure SaveSelection (fname: str255; RefNum: integer; SaveAsSameType: boolean);
  1002.         var
  1003.             slines, spixelsPerLine: integer;
  1004.     begin
  1005.         if info = NoInfo then
  1006.             exit(SaveSelection);
  1007.         if NoSelection or NotRectangular or NotInBounds then
  1008.             exit(SaveSelection);
  1009.         if OpPending then
  1010.             KillRoi;
  1011.         with info^ do begin
  1012.                 with RoiRect do begin
  1013.                         sPixelsPerLine := right - left;
  1014.                         slines := bottom - top;
  1015.                     end;
  1016.                 if (PictureType = PictFile) and SaveAsSameType and (SaveAsWhat <> asRawData) then
  1017.                     SaveAsPICT(fname, RefNum, true)
  1018.                 else
  1019.                     SaveAsTIFF(fname, RefNum, sLines, sPixelsPerLine, true);
  1020.             end;
  1021.     end;
  1022.  
  1023.  
  1024.     procedure SaveAsText (fname: str255; RefNum: integer);
  1025.         var
  1026.             err, f: integer;
  1027.             TheInfo: FInfo;
  1028.             ByteCount: LongInt;
  1029.     begin
  1030.         err := GetFInfo(fname, RefNum, TheInfo);
  1031.         case err of
  1032.             NoErr: 
  1033.                 if TheInfo.fdType <> 'TEXT' then begin
  1034.                         TypeMismatch(fname);
  1035.                         exit(SaveAsText)
  1036.                     end;
  1037.             FNFerr:  begin
  1038.                     err := create(fname, RefNum, FourCharCode(TextCreator), 'TEXT');
  1039.                     if CheckIO(err) <> 0 then
  1040.                         exit(SaveAsText);
  1041.                 end;
  1042.             otherwise
  1043.                 if CheckIO(err) <> 0 then
  1044.                     exit(SaveAsTExt)
  1045.         end;
  1046.         ShowWatch;
  1047.         err := fsopen(fname, RefNum, f);
  1048.         if CheckIO(err) <> 0 then
  1049.             exit(SaveAsText);
  1050.         ByteCount := TextBufSize;
  1051.         err := fswrite(f, ByteCount, ptr(TextBufP));
  1052.         if CheckIO(err) <> 0 then
  1053.             exit(SaveAsText);
  1054.         err := SetEof(f, ByteCount);
  1055.         err := fsclose(f);
  1056.         err := FlushVol(nil, RefNum);
  1057.         if WhatsOnClip = TextOnClip then
  1058.             WhatsOnClip := NothingOnClip;
  1059.     end;
  1060.  
  1061.  
  1062.     procedure SaveAsPICS (fname: str255; fRefNum: integer);
  1063.         const
  1064.             rErr = 'Error Saving PICS file.';
  1065.         type
  1066.             PicHArray = array[1..MaxSlices] of PicHandle;
  1067.             PicHArrayPtr = ^PicHArray;
  1068.         var
  1069.             err: OSErr;
  1070.             TheInfo: FInfo;
  1071.             replacing: boolean;
  1072.             rRefNum, i, SaveCS: integer;
  1073.             frect: rect;
  1074.             {PicH: array[1..MaxSlices] of PicHandle;}
  1075.             PicH: PicHArrayPtr;
  1076.             MinFreeRequired: LongInt;
  1077.             SaveGDevice: GDHandle;
  1078.     begin
  1079.         with info^, Info^.StackInfo^ do begin
  1080.                 if StackInfo = nil then begin
  1081.                         PutError('Only Stacks can be saved in PICS format.');
  1082.                         SaveAsWhat := asTiff;
  1083.                         exit(SaveAsPICS);
  1084.                     end;
  1085.                 if ImageSize > MinFree then
  1086.                     MinFreeRequired := ImageSize
  1087.                 else
  1088.                     MinFreeRequired := MinFree;
  1089.                 if MaxBlock < MinFreeRequired then begin
  1090.                         PutError('Not enough memory available to save in PICS format.');
  1091.                         exit(SaveAsPICS);
  1092.                     end;
  1093.                 PicH := PicHArrayPtr(NewPtr(SizeOf(PicHArray)));
  1094.                 if PicH = nil then
  1095.                     exit(SaveAsPICS);
  1096.                 err := GetFInfo(fname, fRefNum, TheInfo);
  1097.                 if err = NoErr then
  1098.                     with TheInfo do begin
  1099.                             if (fdType <> 'TIFF') and (fdType <> 'PICT') and (fdType <> 'PICS') then begin
  1100.                                     TypeMismatch(fname);
  1101.                                     exit(SaveAsPICS)
  1102.                                 end;
  1103.                             err := FSDelete(fname, fRefNum);
  1104.                         end;
  1105.                 ShowWatch;
  1106.                 err := SetVol(nil, fRefNum);
  1107.                 CreateResFile(fname);
  1108.                 if ResError <> NoErr then
  1109.                     exit(SaveAsPICS);
  1110.                 rRefNum := OpenResFile(fname);
  1111.                 SaveCS := CurrentSlice;
  1112.                 SaveGDevice := GetGDevice;
  1113.                 SetGDevice(osGDevice);
  1114.                 SetPort(GrafPtr(osPort));
  1115.                 with PicRect do
  1116.                     SetRect(frect, 0, 0, right - left, bottom - top);
  1117.                 ClipRect(frect);
  1118.                 LoadLUT(ctable);
  1119.                 pmForeColor(BlackIndex);
  1120.                 pmBackColor(WhiteIndex);
  1121.                 if OldSystem then begin
  1122.                         RGBForeColor(BlackRGB);
  1123.                         RGBBackColor(WhiteRGB);
  1124.                     end;
  1125.                 for i := 1 to nSlices do begin
  1126.                         CurrentSlice := i;
  1127.                         SelectSlice(CurrentSlice);
  1128.                         UpdateTitleBar;
  1129.                         PicH^[i] := OpenPicture(frect);
  1130.                         with osPort^ do
  1131.                             CopyBits(BitMapHandle(portPixMap)^^, BitMapHandle(portPixMap)^^, PicRect, frect, SrcCopy, nil);
  1132.                         ClosePicture;
  1133.                         if (PicH^[i] = nil) or ((PicH^[i] <> nil) and (GetHandleSize(handle(PicH^[i])) <= 10)) then begin
  1134.                                 PutError(rErr);
  1135.                                 leave;
  1136.                             end;
  1137.                         AddResource(handle(PicH^[i]), 'PICT', i - 1 + 128, '');
  1138.                         if ResError <> NoErr then begin
  1139.                                 PutError(rErr);
  1140.                                 leave;
  1141.                             end;
  1142.                         WriteResource(handle(PicH^[i]));
  1143.                         ReleaseResource(handle(PicH^[i]));
  1144.                         if ResError <> NoErr then begin
  1145.                                 PutError(rErr);
  1146.                                 leave;
  1147.                             end;
  1148.                     end; {for}
  1149.                 pmForeColor(ForegroundIndex);
  1150.                 pmBackColor(BackgroundIndex);
  1151.                 SetGDevice(SaveGDevice);
  1152.                 CurrentSlice := SaveCS;
  1153.                 SelectSlice(CurrentSlice);
  1154.                 RemovePath(fname);
  1155.                 TruncateString(fname, maxTitle);
  1156.                 title := fname;
  1157.                 PictureType := PicsFile;
  1158.                 UpdateTitleBar;
  1159.                 CloseResFile(rRefNum);
  1160.                 if ResError = NoErr then
  1161.                     changes := false
  1162.                 else
  1163.                     PutError(rErr);
  1164.                 err := GetFInfo(fname, fRefNum, TheInfo);
  1165.                 TheInfo.fdType := 'PICS';
  1166.                 TheInfo.fdCreator := 'Imag';
  1167.                 err := SetFInfo(fname, fRefNum, TheInfo);
  1168.                 err := FlushVol(nil, fRefNum);
  1169.                 UpdateWindowsMenuItem;
  1170.             end; {with}
  1171.     end;
  1172.  
  1173.  
  1174.     function SuggestedName: str255;
  1175.         var
  1176.             name: str255;
  1177.     begin
  1178.         case SaveAsWhat of
  1179.             asTiff, asPict, asQuickTime, asRawData, asPICS:  begin
  1180.                     name := info^.title;
  1181.                     if name = 'Camera' then
  1182.                         name := 'Untitled';
  1183.                     SuggestedName := name;
  1184.                 end;
  1185.             AsPalette: 
  1186.                 SuggestedName := 'Palette';
  1187.             AsOutline: 
  1188.                 SuggestedName := 'Outline';
  1189.         end;
  1190.     end;
  1191.  
  1192.  
  1193.     function SaveAsHook (item: integer; theDialog: DialogPtr): integer;
  1194.         const
  1195.             EditTextID = 7;
  1196.             TiffID = 9;
  1197.             OutlineID = 14;
  1198.         var
  1199.             i: integer;
  1200.             fname: str255;
  1201.             NameEdited: boolean;
  1202.     begin
  1203.         if item = -1 then {Initialize}
  1204.             SetDlogItem(theDialog, TiffID + ord(SaveAsWhat), 1);
  1205.         fname := GetDString(theDialog, EditTextID);
  1206.         NameEdited := fname <> SuggestedName;
  1207.         if (item >= TiffID) and (item <= OutlineID) then begin
  1208.                 SaveAsWhat := SaveAsWhatType(item - TiffID);
  1209.                 if not NameEdited then begin
  1210.                         SetDString(theDialog, EditTextID, SuggestedName);
  1211.                         SelectdialogItemText(theDialog, EditTextID, 0, 32767);
  1212.                     end;
  1213.                 for i := TiffID to OutlineID do
  1214.                     SetDlogItem(theDialog, i, 0);
  1215.                 SetDlogItem(theDialog, item, 1);
  1216.             end;
  1217.         SaveAsHook := item;
  1218.     end;
  1219.  
  1220.  
  1221.     procedure SaveAs (name: str255; RefNum: integer);
  1222.         const
  1223.             CustomDialogID = 60;
  1224.         var
  1225.             where: Point;
  1226.             reply: SFReply;
  1227.             isSelection: boolean;
  1228.             kind: integer;
  1229.     begin
  1230.         if SaveAsDHookProc=nil
  1231.             then SaveAsDHookProc:=NewRoutineDescriptor(@SaveAsHook, uppDlgHookProcInfo, GetCurrentISA);
  1232.         with info^ do begin
  1233.                 if SaveAllState = SaveAllStage2 then begin
  1234.                         name := title;
  1235.                         RefNum := SaveRefNum;
  1236.                         if SaveAsWhat = AsPalette then
  1237.                             SaveAsWhat := AsTiff;
  1238.                     end
  1239.                 else if (name = '') or ((RefNum = 0) and (pos(':', name) = 0)) then begin
  1240.                         where.v := 50;
  1241.                         where.h := 50;
  1242.                         if (StackInfo = nil) and (SaveAsWhat = asPICS) then
  1243.                             SaveAsWhat := asTIFF;
  1244.                         if (StackInfo <> nil) and (SaveAsWhat = asPICT) then
  1245.                             SaveAsWhat := asTIFF;
  1246.                         if name = '' then
  1247.                             name := SuggestedName;
  1248.                         SFPPutFile(Where, 'Save as?', name, SaveAsDHookProc, reply, CustomDialogID, nil);
  1249.                         if not reply.good then begin
  1250.                                 SaveAllState := NoSaveAll;
  1251.                                 AbortMacro;
  1252.                                 exit(SaveAs);
  1253.                             end;
  1254.                         with reply do begin
  1255.                                 name := fname;
  1256.                                 RefNum := vRefNum;
  1257.                                 DefaultRefNum := RefNum;
  1258.                             end;
  1259.                     end;
  1260.                 if StackInfo <> nil then begin
  1261.                         if (SaveAsWhat <> asOutline) and not ((StackInfo^.StackType = RGBStack) and (StackInfo^.nSlices = 3)) then
  1262.                             KillRoi;
  1263.                         SaveAllState := NoSaveAll;
  1264.                         if not ((SaveAsWhat = asTIFF) or (SaveAsWhat = asQuickTime)  or (SaveAsWhat = asPICS) or (SaveAsWhat = asPalette) or (SaveAsWhat = asOutline)) then begin
  1265.                                 PutError('Stacks can only be saved in TIFF, QuickTime or PICS format.');
  1266.                                 SaveAsWhat := asTIFF;
  1267.                                 exit(SaveAs);
  1268.                             end;
  1269.                     end;
  1270.                 isSelection := RoiShowing and (RoiType = RectRoi);
  1271.                 if SaveAllState = SaveAllStage1 then begin
  1272.                         SaveRefNum := RefNum;
  1273.                         SaveAllState := SaveAllStage2;
  1274.                     end;
  1275.                 case SaveAsWhat of
  1276.                     asTiff, asRawData: 
  1277.                         if isSelection then
  1278.                             SaveSelection(name, RefNum, false)
  1279.                         else
  1280.                             SaveAsTIFF(name, RefNum, 0, 0, false);
  1281.                     asPict: 
  1282.                         if isSelection then
  1283.                             SaveAsPICT(name, RefNum, true)
  1284.                         else
  1285.                             SaveAsPICT(name, RefNum, false);
  1286.                     asQuickTime: 
  1287.                         SaveAsQuickTime(name, RefNum);
  1288.                     asPICS: 
  1289.                         SaveAsPICS(name, RefNum);
  1290.                     AsPalette: 
  1291.                         SaveColorTable(name, RefNum);
  1292.                     AsOutline: 
  1293.                         SaveOutline(name, RefNum);
  1294.                 end; {case}
  1295.                 if (SaveAsWhat = asRawData) and (SaveAllState <> SaveAllStage2) then
  1296.                     SaveAsWhat := asTIFF;
  1297.             end; {with}
  1298.     end;
  1299.  
  1300.  
  1301.     procedure SaveFile;
  1302.         var
  1303.             fname: str255;
  1304.             size: LongInt;
  1305.             ok: boolean;
  1306.     begin
  1307.         if CurrentWindow = ResultsKind then begin
  1308.                 Export('', 0);
  1309.                 exit(SaveFile);
  1310.             end;
  1311.         if CurrentWindow = TextKind then begin
  1312.                 SaveText;
  1313.                 exit(SaveFile);
  1314.             end;
  1315.         if OpPending then
  1316.             KillRoi;
  1317.         with Info^ do begin
  1318.                 fname := title;
  1319.                 size := 0;
  1320.                 if PictureType = TiffFile then
  1321.                     ok := SaveTiffFile(fname, vref, 0, 0, false)
  1322.                 else if PictureType = PictFile then
  1323.                     ok := SavePICTFile(fname, vref, false, false)
  1324.                 else
  1325.                     SaveAs('', 0);
  1326.             end;
  1327.     end;
  1328.  
  1329.  
  1330.     function SaveChanges: integer;
  1331.         const
  1332.             yesID = 1;
  1333.             noID = 2;
  1334.             cancelID = 3;
  1335.         var
  1336.             id: integer;
  1337.             reply: SFReply;
  1338.     begin
  1339.         id := 0;
  1340.         if info^.changes then
  1341.             with info^ do begin
  1342.                     if CommandPeriod or MakingStack or (macro and ((MacroCommand = DisposeC) or (MacroCommand = DisposeAllC))) then begin
  1343.                             SaveChanges := ok;
  1344.                             exit(SaveChanges);
  1345.                         end;
  1346.                     ParamText(title, '', '', '');
  1347.                     InitCursor;
  1348.                     id := alert(600, nil);
  1349.                     if id = yesID then begin
  1350.                             KillRoi;
  1351.                             SaveFile;
  1352.                             InitCursor;
  1353.                         end; {if yes}
  1354.                 end; {if changes}
  1355.         if (id = cancelID) or ((id = yesID) and (info^.changes)) then
  1356.             SaveChanges := cancel
  1357.         else
  1358.             SaveChanges := ok;
  1359.     end;
  1360.  
  1361.  
  1362.     function CloseAWindow (WhichWindow: WindowPtr): integer;
  1363.         var
  1364.             i, kind, n: integer;
  1365.             TempInfo: InfoPtr;
  1366.             TempTextInfo: TextInfoPtr;
  1367.             SizeStr, str: str255;
  1368.             wp: ^WindowPtr;
  1369.             pcrect: rect;
  1370.     begin
  1371.         if WhichWindow = nil then
  1372.             exit(CloseAWindow);
  1373.         kind := WindowPeek(WhichWindow)^.WindowKind;
  1374.         CloseAWindow := ok;
  1375.         if WhichWindow = VideoControl then begin
  1376.                 DisposeDialog(VideoControl);
  1377.                 VideoControl := nil;
  1378.                 exit(CloseAWindow);
  1379.             end;
  1380.         case kind of
  1381.             PicKind:  begin
  1382.                     Info := pointer(WindowPeek(WhichWindow)^.RefCon);
  1383.                     with Info^ do begin
  1384.                             if PicNum = 0 then begin
  1385.                                     beep;
  1386.                                     exit(CloseAWindow);
  1387.                                 end;
  1388.                             if SaveChanges = cancel then begin
  1389.                                     CloseAWindow := cancel;
  1390.                                     exit(CloseAWindow)
  1391.                                 end;
  1392.                             DeleteMenuItem(WindowsMenuH, PicNum + WindowsMenuItems + nTextWindows);
  1393.                             for i := PicNum to nPics - 1 do begin
  1394.                                     PicWindow[i] := PicWindow[i + 1];
  1395.                                     TempInfo := pointer(WindowPeek(PicWindow[i])^.RefCon);
  1396.                                     TempInfo^.PicNum := i
  1397.                                 end;
  1398.                             if PictureType = BlankField then
  1399.                                 BlankFieldInfo := nil;
  1400.                             if (PictureType = FrameGrabberType) and (FrameGrabber = QTvdig) then
  1401.                                 CloseVdig;
  1402.                             if StackInfo <> nil then begin
  1403.                                     with StackInfo^ do
  1404.                                         for i := 1 to nSlices do
  1405.                                             DisposeHandle(PicBaseH[i]);
  1406.                                     DisposePtr(pointer(StackInfo));
  1407.                                 end
  1408.                             else begin
  1409.                                     if not MakingStack then
  1410.                                         DisposeHandle(PicBaseHandle);
  1411.                                 end;
  1412.                             DisposeWindow(WhichWindow);
  1413.                             CloseCPort(osPort);
  1414.                             DisposePtr(ptr(osPort));
  1415.                             DisposeRgn(roiRgn);
  1416.                             if DataH <> nil then
  1417.                                     DisposeHandle(DataH);
  1418.                             nPics := nPics - 1;
  1419.                             OpPending := false;
  1420.                             isInsertionPoint := false;
  1421.                             DisposePtr(pointer(Info));
  1422.                             Info := NoInfo;
  1423.                             if (nPics = 0) and (not finished) then
  1424.                                 with info^ do begin
  1425.                                         LoadLUT(info^.cTable);
  1426.                                         if (LutMode = GrayScale) or (LutMode = CustomGrayScale) then
  1427.                                             DrawMap;
  1428.                                     end;
  1429.                             PicLeft := PicLeftBase;
  1430.                             PicTop := PicTopBase;
  1431.                         end;
  1432.                 end; {PicKind}
  1433.             HistoKind:  begin
  1434.                     DisposeWindow(HistoWindow);
  1435.                     HistoWindow := nil;
  1436.                     ContinuousHistogram := false;
  1437.                 end;
  1438.             ProfilePlotKind, CalibrationPlotKind:  begin
  1439.                     DisposeWindow(PlotWindow);
  1440.                     PlotWindow := nil;
  1441.                     KillPicture(PlotPICT);
  1442.                     PlotPICT := nil;
  1443.                 end;
  1444.             ResultsKind:  begin
  1445.                     DisposeWindow(ResultsWindow);
  1446.                     ResultsWindow := nil;
  1447.                     TEDispose(ListTE);
  1448.                 end;
  1449.             TextKind:  begin
  1450.                     TextInfo := TextInfoPtr(WindowPeek(WhichWindow)^.RefCon);
  1451.                     if TextInfo <> nil then
  1452.                         with TextInfo^ do begin
  1453.                                 if SaveTextChanges = cancel then begin
  1454.                                         CloseAWindow := cancel;
  1455.                                         exit(CloseAWindow)
  1456.                                     end;
  1457.                                 DisposeWindow(TextWindowPtr);
  1458.                                 DeleteMenuItem(WindowsMenuH, WindowsMenuItems - 1 + WindowNum);
  1459.                                 TEDispose(TextTE);
  1460.                                 DisposePtr(ptr(TextInfo));
  1461.                                 TextInfo := nil;
  1462.                                 for i := WindowNum to nTextWindows - 1 do begin
  1463.                                         TextWindow[i] := TextWindow[i + 1];
  1464.                                         TempTextInfo := pointer(WindowPeek(TextWindow[i])^.RefCon);
  1465.                                         TempTextInfo^.WindowNum := i
  1466.                                     end;
  1467.                                 nTextWindows := nTextWindows - 1;
  1468.                             end;
  1469.                 end;
  1470.             PasteControlKind:  begin
  1471.                     GetWindowRect(PasteControl, pcrect);
  1472.                     with pcrect do begin
  1473.                             PasteControlLeft := left;
  1474.                             PasteControlTop := top;
  1475.                         end;
  1476.                     DisposeWindow(PasteControl);
  1477.                     PasteControl := nil;
  1478.                     wp := pointer(GhostWindow);
  1479.                     wp^ := nil;
  1480.                 end;
  1481.             otherwise
  1482.                 ;
  1483.         end; {case}
  1484.     end;
  1485.  
  1486.  
  1487.     procedure DoClose;
  1488.         var
  1489.             ignore: integer;
  1490.             fwptr: WindowPtr;
  1491.             kind: integer;
  1492.     begin
  1493.         fwptr := FrontWindow;
  1494.         if fwptr <> nil then begin
  1495.                 if fwptr = VideoControl then begin
  1496.                         DisposeDialog(VideoControl);
  1497.                         VideoControl := nil;
  1498.                         exit(DoClose);
  1499.                     end;
  1500.                 kind := WindowPeek(fwptr)^.WindowKind;
  1501.                 if (kind = PicKind) or (kind = ProfilePlotKind) or (kind = CalibrationPlotKind) or (kind = HistoKind) or (Kind = PasteControlKind) or (Kind = ResultsKind) or (Kind = TextKind) then
  1502.                     ignore := CloseAWindow(fwptr);
  1503.             end;
  1504.     end;
  1505.  
  1506.  
  1507.     procedure Read4BitTIFF (f: integer);
  1508.         var
  1509.             vloc, hloc, i: integer;
  1510.             ByteCount, count: LongInt;
  1511.             err: OSErr;
  1512.             UnpackedLine, PackedLine: LineType;
  1513.     begin
  1514.         with info^ do begin
  1515.                 if PixelsPerLine > MaxLine then
  1516.                     exit(Read4BitTIFF);
  1517.                 ByteCount := (PixelsPerLine + 1) div 2;
  1518.                 for vloc := 0 to nLines - 1 do begin
  1519.                         err := FSRead(f, ByteCount, @PackedLine);
  1520.                         i := 0;
  1521.                         for hloc := 0 to PixelsPerLine - 1 do
  1522.                             if odd(hloc) then begin
  1523.                                     UnpackedLine[hloc] := bsl(band(PackedLine[i], $F), 4);
  1524.                                     i := i + 1;
  1525.                                 end
  1526.                             else
  1527.                                 UnpackedLine[hloc] := band(PackedLine[i], $F0);
  1528.                         PutLine(0, vloc, PixelsPerLine, UnpackedLine);
  1529.                     end;
  1530.             end; {with}
  1531.     end;
  1532.  
  1533.  
  1534. {$POP}
  1535.  
  1536.     procedure CheckFileSize(f:integer; var size: LongInt; offset: LongInt);
  1537.     {Check to make sure we don't read past the end of file.}
  1538.     var
  1539.         FileSize: LongInt;
  1540.         err: OSErr;
  1541.     begin
  1542.         err := GetEof(f, FileSize);
  1543.         if (offset + size) > FileSize then begin
  1544.            size := FileSize - offset;
  1545.            if size < 0 then size := 0;
  1546.         end;
  1547.     end;
  1548.  
  1549.  
  1550.     procedure ReadStackSlices (f, nExtraImages: integer; var table: TiffIFDTablePtr);
  1551.         var
  1552.             i, err, SaveCS: integer;
  1553.             h: handle;
  1554.             DataSize: LongInt;
  1555.             PartialStack: boolean;
  1556.     begin
  1557.         ShowMessage(CmdPeriodToStop);
  1558.         PartialStack := false;
  1559.         with info^ do begin
  1560.                 StackInfo := StackInfoPtr(NewPtr(SizeOf(StackInfoRec)));
  1561.                 if StackInfo = nil then
  1562.                     exit(ReadStackSlices);
  1563.             end;
  1564.         with info^, info^.StackInfo^ do begin
  1565.                 nSlices := nExtraImages + 1;
  1566.                 CurrentSlice := TempStackInfo.CurrentSlice;
  1567.                 if (CurrentSlice < 1) or (CurrentSlice > nSlices) then
  1568.                     CurrentSlice := 1;
  1569.                 SliceSpacing := TempStackInfo.SliceSpacing;
  1570.                 FrameInterval := TempStackInfo.FrameInterval;
  1571.                 StackType := TempStackInfo.StackType;
  1572.                 SaveCS := CurrentSlice;
  1573.                 PicBaseH[1] := PicBaseHandle;
  1574.                 revertable := false;
  1575.                 for i := 2 to nSlices do begin
  1576.                         h := GetBigHandle(PixMapSize);
  1577.                         if h = nil then begin
  1578.                                 nSlices := i - 1;
  1579.                                 PutError(concat('Not enough memory to open all ', long2str(nExtraImages + 1), ' slices in the stack.'));
  1580.                                 PartialStack := true;
  1581.                                 leave;
  1582.                             end;
  1583.                         PicBaseH[i] := h;
  1584.                         CurrentSlice := i;
  1585.                         SelectSlice(i);
  1586.                         UpdateTitleBar;
  1587.                         DataSize := ImageSize;
  1588.                         err := SetFPos(f, fsFromStart, table^[i - 1].offset);
  1589.                         CheckFileSize(f, DataSize, table^[i - 1].offset);
  1590.                         if DataSize > 0 then
  1591.                             err := fsread(f, DataSize, h^);
  1592.                         if odd(PixelsPerLine) then
  1593.                             UnpackLines;
  1594.                         if InvertedImage then
  1595.                             InvertPic;
  1596.                         UpdatePicWindow;
  1597.                         if CommandPeriod then begin
  1598.                                 beep;
  1599.                                 if i < nSlices then
  1600.                                     PartialStack := true;
  1601.                                 nSlices := i;
  1602.                                 wait(60);
  1603.                                 leave;
  1604.                             end;
  1605.                     end; {for}
  1606.                 CurrentSlice := SaveCS;
  1607.                 if CurrentSlice > nSlices then
  1608.                     CurrentSlice := 1;
  1609.                 SelectSlice(CurrentSlice);
  1610.                 if PartialStack then begin
  1611.                         vref := 0;
  1612.                         PictureType := NewPicture;
  1613.                         title := concat(title, '@');
  1614.                     end;
  1615.                 UpdateTitleBar;
  1616.                 UpdateWindowsMenuItem;
  1617.             end;
  1618.     end;
  1619.  
  1620.  
  1621.     procedure OpenStack (f: integer);
  1622.         var
  1623.             table: TiffIFDTablePtr;
  1624.             i, nExtraImages: integer;
  1625.             where: LongInt;
  1626.     begin
  1627.         table := TiffIFDTablePtr(NewPtr(SizeOf(TiffIFDTable)));
  1628.         if table = nil then
  1629.             exit(OpenStack);
  1630.         nExtraImages := TempStackInfo.nSlices - 1;
  1631.         with info^ do begin
  1632.                 where := ImageDataOffset;
  1633.                 for i := 1 to nExtraImages do
  1634.                     with table^[i] do begin
  1635.                             iWidth := PixelsPerLine;
  1636.                             iHeight := nLines;
  1637.                             where := where + ImageSize;
  1638.                             Offset := where;
  1639.                             invert := false;
  1640.                         end;
  1641.                 ReadStackSlices(f, nExtraImages, table);
  1642.             end;
  1643.     end;
  1644.  
  1645.  
  1646.     procedure OpenExtraTiffImages (f: integer; NextTiffIFD: LongInt);
  1647.         var
  1648.             table: TiffIFDTablePtr;
  1649.             TiffInfo: TiffInfoRec;
  1650.             i, nExtraImages: integer;
  1651.             AllSameSize: boolean;
  1652.     begin
  1653.         table := TiffIFDTablePtr(NewPtr(SizeOf(TiffIFDTable)));
  1654.         if table = nil then
  1655.             exit(OpenExtraTiffImages);
  1656.         nExtraImages := 0;
  1657.         repeat
  1658.             if not OpenTiffDirectory(f, NextTiffIFD, TiffInfo, false) then
  1659.                 exit(OpenExtraTiffImages);
  1660.             nExtraImages := nExtraImages + 1;
  1661.             with TiffInfo, table^[nExtraImages] do begin
  1662.                     iWidth := width;
  1663.                     iHeight := height;
  1664.                     Offset := OffsetToData;
  1665.                     invert := ZeroIsBlack;
  1666.                     NextTiffIFD := NextIFD;
  1667.                 end;
  1668.         until (NextTiffIFD = 0) or (nExtraImages = MaxSlices);
  1669.         AllSameSize := true;
  1670.         with info^ do begin
  1671.                 for i := 1 to nExtraImages do
  1672.                     AllSameSize := AllSameSize and (PixelsPerLine = table^[i].iWidth) and (nLines = table^[i].iHeight);
  1673.                 if AllSameSize and not odd(PixelsPerLine) then
  1674.                     ReadStackSlices(f, nExtraImages, table);
  1675.             end;
  1676.     end;
  1677.  
  1678.     procedure OpenPlanarRGBTiff(f: integer);
  1679.     var
  1680.         row, ignore, SaveRow: integer;
  1681.         NextUpdate, count: LongInt;
  1682.         rLine, gLine, bLine: LineType;
  1683.         err: OSErr;
  1684.         MaskRect: rect;
  1685.     begin
  1686.         with info^ do begin
  1687.             err := SetFPos(f, fsFromStart, ImageDataOffset);
  1688.             SelectSlice(1);
  1689.             for row:=0 to nLines - 1 do begin
  1690.                 count := PixelsPerLine;
  1691.                 err := fsread(f, count, @rLine);
  1692.                 PutLine(0, row, PixelsPerLine, rLine);
  1693.             end;
  1694.             InvertPic;
  1695.             ResetGrayMap;
  1696.             UpdatePicWindow; 
  1697.             SelectSlice(2);
  1698.             for row:=0 to nLines - 1 do begin
  1699.                 count := PixelsPerLine;
  1700.                 err := fsread(f, count, @gLine);
  1701.                 PutLine(0, row, PixelsPerLine, gLine);
  1702.             end; 
  1703.             InvertPic;
  1704.             UpdatePicWindow; 
  1705.             SelectSlice(3);
  1706.             for row:=0 to nLines - 1 do begin
  1707.                 count := PixelsPerLine;
  1708.                 err := fsread(f, count, @bLine);
  1709.                 PutLine(0, row, PixelsPerLine, bLine);
  1710.             end; 
  1711.             InvertPic;
  1712.             UpdatePicWindow; 
  1713.             with StackInfo^ do begin
  1714.                 CurrentSlice := 1;
  1715.                 SelectSlice(CurrentSlice);
  1716.                 StackType := rgbStack;
  1717.             end;
  1718.             UpdateTitleBar;
  1719.             OpeningRGB := true;
  1720.         end; {with}
  1721.     end;
  1722.  
  1723.  
  1724.     procedure OpenRGBTiff(f: integer; TiffInfo: TiffInfoRec);
  1725.     const
  1726.         bufsize = 12000;
  1727.     var
  1728.         i, row, pixel, rgbPixel, ignore, SaveRow: integer;
  1729.         NextUpdate, count: LongInt;
  1730.         buffer: packed array [0 .. bufsize] of byte;
  1731.         rLine, gLine, bLine: LineType;
  1732.         err: OSErr;
  1733.         MaskRect: rect;
  1734.     begin
  1735.         with info^ do begin
  1736.             if PixelsPerLine > MaxLine then
  1737.                 exit(OpenRGBTiff);
  1738.             if not MakeStackFromWindow then
  1739.                 exit(OpenRGBTiff);
  1740.             if not AddSlice(false) then begin
  1741.                     info^.changes := false;
  1742.                     ignore := CloseAWindow(info^.wptr);
  1743.                     exit(OpenRGBTiff);
  1744.                 end;
  1745.             if not AddSlice(false) then begin
  1746.                     info^.changes := false;
  1747.                     ignore := CloseAWindow(info^.wptr);
  1748.                     exit(OpenRGBTiff);
  1749.                 end;
  1750.             if TiffInfo.PlanarConfig <> 1 then begin
  1751.                 OpenPlanarRGBTiff(f);
  1752.                 exit(OpenRGBTiff);
  1753.             end;
  1754.             if ScreenDepth <> 8 then begin
  1755.                 SelectAll(false);
  1756.                 DoOperation(EraseOp);
  1757.                 changes:= false;
  1758.                 KillRoi;
  1759.             end;
  1760.             ResetGrayMap;
  1761.             SaveRow:=0;
  1762.             NextUpdate:=TickCount+6;
  1763.             err := SetFPos(f, fsFromStart, ImageDataOffset);
  1764.             count := 0;
  1765.             for row:=0 to nLines - 1 do begin
  1766.                 for pixel := 0 to PixelsPerLine - 1 do begin
  1767.                     if count <= 0 then begin
  1768.                         count := bufsize;
  1769.                         err := fsread(f, count, @buffer);
  1770.                         if err <> -39 then {eof error}
  1771.                             if CheckIO(err) <> noErr then
  1772.                                 exit(OpenRGBTiff);
  1773.                         rgbPixel := 0;
  1774.                     end;
  1775.                     rLine[pixel] := 255 - buffer[rgbPixel];
  1776.                     gLine[pixel] := 255 - buffer[rgbPixel + 1];
  1777.                     bLine[pixel] := 255 - buffer[rgbPixel + 2];
  1778.                     rgbPixel := rgbPixel + 3;
  1779.                     count := count - 3;
  1780.                 end;
  1781.                 SelectSlice(1);
  1782.                 PutLine(0, row, PixelsPerLine, rLine);
  1783.                 if TickCount>=NextUpdate then begin
  1784.                     SetRect(MaskRect, 0, SaveRow, PixelsPerLine, row+1);
  1785.                     UpdateScreen(MaskRect);
  1786.                     SaveRow:=row + 1;
  1787.                     NextUpdate:=TickCount+6;
  1788.                 end;
  1789.                 SelectSlice(2);
  1790.                 PutLine(0, row, PixelsPerLine, gLine);
  1791.                 SelectSlice(3);
  1792.                 PutLine(0, row, PixelsPerLine, bLine);
  1793.             end; {for}
  1794.             with StackInfo^ do begin
  1795.                 CurrentSlice := 1;
  1796.                 SelectSlice(CurrentSlice);
  1797.                 StackType := rgbStack;
  1798.             end;
  1799.             SetRect(MaskRect, 0, SaveRow, PixelsPerLine, nLines);
  1800.             UpdateScreen(MaskRect);
  1801.             UpdateTitleBar;
  1802.             OpeningRGB := true;
  1803.         end; {with}
  1804.     end;
  1805.     
  1806.  
  1807.     function OpenFile (fname: str255; vnum: integer): boolean;
  1808.         var
  1809.             ticks, ByteCount, i, DataSize, NextTiffIFD: LongInt;
  1810.             err: OSErr;
  1811.             f: integer;
  1812.             line, pixel: integer;
  1813.             iptr, p: ptr;
  1814.             SaveInfo: InfoPtr;
  1815.             TiffInfo: TiffInfoRec;
  1816.             isRGBTiff: boolean;
  1817.     begin
  1818.         OpenFile := false;
  1819.         ShowWatch;
  1820.         err := fsopen(fname, vNum, f);
  1821.         SaveInfo := Info;
  1822.         iptr := NewPtr(SizeOf(PicInfo));
  1823.         if iptr = nil then begin
  1824.                 PutMemoryAlert;
  1825.                 err := fsclose(f);
  1826.                 exit(OpenFile)
  1827.             end;
  1828.         Info := pointer(iptr);
  1829.         CloneInfo(SaveInfo^, Info^);
  1830.         with Info^ do begin
  1831.                 ColorMapOffset := 0;
  1832.                 if not OpenHeader(f, fname, vnum, TiffInfo) then begin
  1833.                         DisposePtr(iptr);
  1834.                         err := fsclose(f);
  1835.                         Info := SaveInfo;
  1836.                         exit(OpenFile)
  1837.                     end;
  1838.                 if WhatToOpen = OpenTIFF then begin
  1839.                     NextTiffIFD := TiffInfo.NextIFD;
  1840.                     isRGBTiff := TiffInfo.SamplesPerPixel = 3;
  1841.                 end else begin
  1842.                     NextTiffIFD := 0;
  1843.                     isRGBTiff := false;
  1844.                 end;
  1845.                 p := GetImageMemory(SaveInfo);
  1846.                 if p = nil then begin
  1847.                         err := fsclose(f);
  1848.                         exit(OpenFile)
  1849.                     end;
  1850.                 PicBaseAddr := p;
  1851.                 MakeNewWindow(fname);
  1852.                 err := SetFPos(f, fsFromStart, ImageDataOffset);
  1853.                 if PictureType = FourBitTIFF then
  1854.                     Read4BitTIFF(f)
  1855.                 else if not isRGBTiff then begin
  1856.                         DataSize := nlines * PixelsPerLine;
  1857.                         CheckFileSize(f, DataSize, ImageDataOffset);
  1858.                         if DataSize > 0 then
  1859.                             err := fsread(f, DataSize, PicBaseAddr);
  1860.                         if CheckIO(err) <> NoErr then begin
  1861.                                 err := fsclose(f);
  1862.                                 exit(OpenFile)
  1863.                             end;
  1864.                     end;
  1865.                 if odd(PixelsPerLine) and (PictureType <> FourBitTiff) then
  1866.                     UnpackLines;
  1867.                 if (PictureType = Imported) and (ImportInvert or (WhatToImport = ImportMCID)) then
  1868.                     InvertedImage := true;
  1869.                 if InvertedImage then
  1870.                     InvertPic;
  1871.                 if PictureType = FourBitTIFF then
  1872.                     PictureType := imported;
  1873.                 if (ColorMapOffset > 0) and (fileVersion = 0) then begin
  1874.                         FixColors; {Fix colors, if necessary, of imported color TIFF files.}
  1875.                         WhatToUndo := NothingToUndo;
  1876.                     end;
  1877.                 vref := vnum;
  1878.                 if PixMapSize > UndoBufSize then
  1879.                     PutWarning;
  1880.                 revertable := true;
  1881.             end; {with}
  1882.             if isRGBTiff then
  1883.                 OpenRGBTiff(f, TiffInfo)
  1884.             else if TempStackInfo.nSlices > 0 then
  1885.                 OpenStack(f)
  1886.             else if NextTiffIFD > 0 then
  1887.             OpenExtraTiffImages(f, NextTiffIFD);
  1888.         err := fsclose(f);
  1889.         OpenFile := true;
  1890.     end;
  1891.  
  1892.  
  1893. {$PUSH}
  1894. {$D-}
  1895.  
  1896.     procedure ScaleToEightBits (f: integer);
  1897.         type
  1898.             PixelLUTType = packed array[0..65535] of byte;
  1899.             PixelLUTPtr = ^PixelLUTType;
  1900.             IntLineType = array[0..MaxLine] of integer;
  1901.         var
  1902.             line: LineType;
  1903.             i, j, value, LineSize, offset: LongInt;
  1904.             ScaleFactor: extended;
  1905.             hloc, vloc, wwidth, wheight, IntValue, SaveBytesPerRow: integer;
  1906.             PixelLUT: PixelLUTPtr;
  1907.             str1, str2: str255;
  1908.             err: integer;
  1909.             aLine: IntLineType;
  1910.             LinesPerUpdate: integer;
  1911.  
  1912.         procedure reset;
  1913.             var
  1914.                 DataSize, SliceOffset: LongInt;
  1915.                 p: ptr;
  1916.         begin
  1917.             with info^ do begin
  1918.                     if StackInfo <> nil then
  1919.                         SliceOffset := ImageSize * 2 * (StackInfo^.CurrentSlice - 1)
  1920.                     else
  1921.                         SliceOffset := 0;
  1922.                     err := SetFPos(f, fsFromStart, ImageDataOffset + SliceOffset);
  1923.                     if DataH <> nil then begin
  1924.                             if offset = -1 then begin
  1925.                                     hlock(DataH);
  1926.                                     DataSize := ImageSize * 2;
  1927.                                     CheckFileSize(f, DataSize, ImageDataOffset);
  1928.                                     if DataSize > 0 then
  1929.                                         err := fsread(f, DataSize, DataH^);
  1930.                                 end;
  1931.                             offset := 0
  1932.                         end;
  1933.                 end;
  1934.         end;
  1935.  
  1936.  
  1937.         procedure GetIntLine (var line: IntLineType);
  1938.             type
  1939.                 atype = packed array[1..2] of char;
  1940.             var
  1941.                 p: ptr;
  1942.                 a: atype;
  1943.                 c: char;
  1944.                 i: integer;
  1945.         begin
  1946.             with info^ do begin
  1947.                     if DataH <> nil then begin
  1948.                             p := ptr(ord4(DataH^) + offset);
  1949.                             if (offset + LineSize) <= (PixMapSize * 2) then
  1950.                                 BlockMove(p, @line, LineSize);
  1951.                             offset := offset + LineSize;
  1952.                         end
  1953.                     else
  1954.                         err := fsread(f, LineSize, @line);
  1955.                     if LittleEndian then
  1956.                         for i := 0 to LineSize div 2 - 1 do begin
  1957.                                 a := atype(line[i]);
  1958.                                 c := a[1];
  1959.                                 a[1] := a[2];
  1960.                                 a[2] := c;
  1961.                                 line[i] := integer(a)
  1962.                             end;
  1963.                 end;
  1964.         end;
  1965.         
  1966.         procedure FindMinAndMax;
  1967.         var
  1968.             vloc, hloc: integer;
  1969.             value: LongInt;
  1970.         begin
  1971.             with info^ do begin
  1972.                 AbsoluteMin := 999999;
  1973.                 AbsoluteMax := -999999;
  1974.                 for vloc := 0 to nlines - 1 do begin
  1975.                         if (vloc mod LinesPerUpdate) = 0 then
  1976.                             ShowAnimatedWatch;
  1977.                         GetIntLine(aLine);
  1978.                         for hloc := 0 to PixelsPerLine - 1 do begin
  1979.                                 value := aLine[hloc];
  1980.                                 if (DataType = SixteenBitsUnsigned) and (value < 0) then
  1981.                                     value := value + 65536;
  1982.                                 if value > AbsoluteMax then
  1983.                                     AbsoluteMax := value;
  1984.                                 if value < AbsoluteMin then begin
  1985.                                     if ImportingDicom then begin
  1986.                                         if value <> -32767 then AbsoluteMin := value
  1987.                                     end else
  1988.                                         AbsoluteMin := value;
  1989.                                 end; {value <AbsoluteMin}
  1990.                             end {for hloc:=}
  1991.                     end;{for vloc := }
  1992.                 if (CurrentMin = 0) and (CurrentMax = 0) then begin
  1993.                         CurrentMin := AbsoluteMin;
  1994.                         CurrentMax := AbsoluteMax;
  1995.                     end;
  1996.                 reset;
  1997.             end; {with}
  1998.         end;
  1999.  
  2000.     begin
  2001.         with info^ do begin
  2002.                 PixelLUT := PixelLUTPtr(NewPtr(SizeOf(PixelLUTType)));
  2003.                 if PixelLUT = nil then begin
  2004.                         if DataH <> nil then begin
  2005.                                 DisposeHandle(DataH);
  2006.                                 DataH := nil
  2007.                             end;
  2008.                         PutError('Not enough memory to do 16 to 8-bit scaling.');
  2009.                         AbortMacro;
  2010.                         exit(ScaleToEightBits);
  2011.                     end;
  2012.                 offset := -1;
  2013.                 reset;
  2014.                 LineSize := PixelsPerLine * 2;
  2015.                 LinesPerUpdate := 40000 div LineSize;
  2016.                 if (AbsoluteMin = 0) and (AbsoluteMax = 0) then
  2017.                     FindMinAndMax;
  2018.                 str1 := concat('min=', long2str(CurrentMin), ' (', long2str(AbsoluteMin), ')', crStr, 'max=', long2str(CurrentMax), ' (', long2str(AbsoluteMax), ')');
  2019.                 ScaleFactor := 253.0 / (CurrentMax - CurrentMin);
  2020.                 RealToString(ScaleFactor, 1, 4, str2);
  2021.                 ShowMessage(concat(str1, crStr, 'scale factor= ', str2));
  2022.                 j := 0;
  2023.                 for i := CurrentMin to CurrentMax do begin
  2024.                         PixelLUT^[j] := round((i - CurrentMin) * ScaleFactor + 1);
  2025.                         j := j + 1;
  2026.                     end;
  2027.                 for vloc := 0 to nlines - 1 do begin
  2028.                         if (vloc mod LinesPerUpdate) = 0 then
  2029.                             ShowAnimatedWatch;
  2030.                         GetIntLine(aLine);
  2031.                         for hloc := 0 to PixelsPerLine - 1 do begin
  2032.                                 value := aLine[hloc];
  2033.                                 if (DataType = SixteenBitsUnsigned) and (value < 0) then
  2034.                                     value := value + 65536;
  2035.                                 if value < CurrentMin then
  2036.                                     value := CurrentMin;
  2037.                                 if value > CurrentMax then
  2038.                                     value := CurrentMax;
  2039.                                 line[hloc] := PixelLUT^[value - CurrentMin];
  2040.                                 i := i + 1;
  2041.                             end;
  2042.                         PutLine(0, vloc, PixelsPerLine, line);
  2043.                     end;
  2044.                 if fit = StraightLine then begin
  2045.                         nCoefficients := 2;
  2046.                         coefficient[2] := (CurrentMin - CurrentMax) / 253.0;
  2047.                         coefficient[1] := CurrentMax - coefficient[2];
  2048.                         nKnownValues := 0;
  2049.                         ZeroClip := false;
  2050.                     end;
  2051.                 DisposePtr(ptr(PixelLUT));
  2052.                 if DataH <> nil then begin
  2053.                         DisposeHandle(DataH);
  2054.                         DataH := nil
  2055.                     end;
  2056.                 UpdateTitleBar;
  2057.             end; {with}
  2058.     end;
  2059.  
  2060.  
  2061.     procedure RescaleToEightBits;
  2062.         var
  2063.             range: LongInt;
  2064.             err: OSErr;
  2065.             f: integer;
  2066.     begin
  2067.         with info^ do begin
  2068.                 ShowWatch;
  2069.                 KillRoi;
  2070.                 DisableDensitySlice;
  2071.                 err := fsopen(title, vref, f);
  2072.                 if CheckIO(err) <> 0 then
  2073.                     exit(RescaleToEightBits);
  2074.                 range := CurrentMax - CurrentMin;
  2075.                 if ColorStart > 0 then
  2076.                     CurrentMax := CurrentMax - round((ColorStart / 255.0) * range)
  2077.                 else
  2078.                     CurrentMax := AbsoluteMax;
  2079.                 if ColorEnd < 255 then
  2080.                     CurrentMin := CurrentMin + round(((255 - ColorEnd) / 255.0) * range)
  2081.                 else
  2082.                     CurrentMin := AbsoluteMin;
  2083.                 ScaleToEightBits(f);
  2084.                 err := fsclose(f);
  2085.                 InvertPic;
  2086.                 UpdatePicWindow;
  2087.                 ResetMap;
  2088.                 if fit <> uncalibrated then
  2089.                     GenerateValues;
  2090.             end;
  2091.     end;
  2092.  
  2093.  
  2094.     procedure Import16BitSlices (f: integer);
  2095.         var
  2096.             i, err: integer;
  2097.             h: handle;
  2098.             DataSize, nImages, MaxImages, FileSize: LongInt;
  2099.     begin
  2100.         with info^ do begin
  2101.                 nImages := ImportCustomSlices;
  2102.                 err := GetEof(f, FileSize);
  2103.                 MaxImages := (FileSize - ImportCustomOffset) div (ImageSize * 2);
  2104.                 if nImages > MaxImages then
  2105.                     nImages := MaxImages;
  2106.                 if nImages < 2 then
  2107.                     exit(Import16BitSlices);
  2108.                 ShowMessage(CmdPeriodToStop);
  2109.                 StackInfo := StackInfoPtr(NewPtr(SizeOf(StackInfoRec)));
  2110.                 if StackInfo = nil then
  2111.                     exit(Import16BitSlices);
  2112.             end; {with}
  2113.         with info^, info^.StackInfo^ do begin
  2114.                 nSlices := nImages;
  2115.                 SliceSpacing := 0.0;
  2116.                 FrameInterval := 0.0;
  2117.                 StackType := VolumeStack;
  2118.                 PicBaseH[1] := PicBaseHandle;
  2119.                 revertable := false;
  2120.                 for i := 2 to nSlices do begin
  2121.                         h := NewHandle(PixMapSize);
  2122.                         if h = nil then begin
  2123.                                 nSlices := i - 1;
  2124.                                 leave;
  2125.                             end;
  2126.                         PicBaseH[i] := h;
  2127.                         CurrentSlice := i;
  2128.                         SelectSlice(i);
  2129.                         UpdateTitleBar;
  2130.                         DataSize := ImageSize;
  2131.                         AbsoluteMin := 0;
  2132.                         AbsoluteMax := 0;
  2133.                         CurrentMin := 0;
  2134.                         CurrentMax := 0;
  2135.                         if not ImportAutoScale then begin
  2136.                                 if ((ImportMax - ImportMin) > 65536.0) or (ImportMin > ImportMax) then begin
  2137.                                         ImportMin := 0.0;
  2138.                                         ImportMax := 255;
  2139.                                     end;
  2140.                                 CurrentMin := round(ImportMin);
  2141.                                 CurrentMax := round(ImportMax);
  2142.                             end;
  2143.                         ScaleToEightBits(f);
  2144.                         InvertPic;
  2145.                         UpdatePicWindow;
  2146.                         if CommandPeriod then begin
  2147.                                 beep;
  2148.                                 nSlices := i;
  2149.                                 wait(60);
  2150.                                 leave;
  2151.                             end;
  2152.                     end; {for}
  2153.                 if (MaxBlock < MinFree) and (nSlices > 1) then begin
  2154.                         repeat
  2155.                             DisposeHandle(PicBaseH[nSlices]);
  2156.                             nSlices := nSlices - 1;
  2157.                         until (MaxBlock > MinFree) or (nSlices = 1);
  2158.                         PutError(concat('Not enough memory to open all ', long2str(nImages), ' slices in the stack.'));
  2159.                     end;
  2160.                 CurrentSlice := 1;
  2161.                 SelectSlice(CurrentSlice);
  2162.                 if ImportCalibrate and  ImportAutoScale then begin
  2163.                     RemoveDensityCalibration;
  2164.                     ImportCalibrate := false;
  2165.                 end;
  2166.                 UpdateTitleBar;
  2167.                 UpdateWindowsMenuItem;
  2168.             end;
  2169.     end;
  2170.  
  2171.  
  2172.     function Import16BitFile (fname: str255; vnum: integer): boolean;
  2173.         var
  2174.             ticks, ByteCount, i: LongInt;
  2175.             err: OSErr;
  2176.             f: integer;
  2177.             line, pixel: integer;
  2178.     begin
  2179.         Import16BitFile := false;
  2180.         if ImportCustomWidth > MaxLine then
  2181.             exit(Import16BitFile);
  2182.         if not NewPicWindow(fname, ImportCustomWidth, ImportCustomHeight) then
  2183.             exit(Import16BitFile);
  2184.         ShowWatch;
  2185.         err := fsopen(fname, vNum, f);
  2186.         with info^ do begin
  2187.                 PictureType := imported;
  2188.                 ImageDataOffset := ImportCustomOffset;
  2189.                 DataType := ImportCustomDepth;
  2190.                 vref := vnum;
  2191.                 AbsoluteMin := 0;
  2192.                 AbsoluteMax := 0;
  2193.                 CurrentMin := 0;
  2194.                 CurrentMax := 0;
  2195.                 LittleEndian := ImportSwapBytes;
  2196.                 if ImportCalibrate then begin
  2197.                     fit := StraightLine;
  2198.                     nCoefficients := 2;
  2199.                     coefficient[1] := 0.0; {ScaleToEightBits changes these coefficient}
  2200.                     coefficient[2] := 1.0;
  2201.                 end else
  2202.                     RemoveDensityCalibration;
  2203.                 if not ImportAutoScale then begin
  2204.                         if ((ImportMax - ImportMin) > 65536.0) or (ImportMin > ImportMax) then begin
  2205.                                 ImportMin := 0.0;
  2206.                                 ImportMax := 255;
  2207.                             end;
  2208.                         CurrentMin := round(ImportMin);
  2209.                         CurrentMax := round(ImportMax);
  2210.                     end;
  2211.                 DataH := GetBigHandle(PixMapSize * 2);
  2212.                 ScaleToEightBits(f);
  2213.                 if ImportCustomSlices > 1 then
  2214.                     Import16BitSlices(f);
  2215.                 err := fsclose(f);
  2216.                 InvertPic;
  2217.                 if PixMapSize > UndoBufSize then
  2218.                     PutWarning;
  2219.                 revertable := false;
  2220.             end; {with}
  2221.         Import16BitFile := true;
  2222.     end;
  2223.  
  2224.  
  2225.     procedure InitPictBuffer (howBig: LongInt);
  2226.     begin
  2227.         repeat
  2228.             PictBuffer := NewPtr(howBig);
  2229.             if PictBuffer = nil then
  2230.                 howBig := howBig div 2;
  2231.         until PictBuffer <> nil;
  2232.         DisposePtr(PictBuffer);
  2233.         PictBuffer := NewPtr(howBig div 2);
  2234.     end;
  2235.  
  2236.  
  2237.     procedure FillPictBuffer;
  2238.         var
  2239.             count: LongInt;
  2240.             err: OSErr;
  2241.     begin
  2242.         count := GetPtrSize(PictBuffer);
  2243.         if not fitsInPictBuffer then begin
  2244.                 err := FSRead(PictF, count, PictBuffer);
  2245.                 if err <> NoErr then
  2246.                     PictReadErr := true;
  2247.             end;
  2248.         bytesInPictBuffer := count;
  2249.         curPictBufPtr := PictBuffer;
  2250.     end;
  2251.  
  2252.  
  2253.     procedure GetPICTData (dataPtr: Ptr; byteCount: Integer);
  2254.     {Input picture spooler routine taken from Apple's PICTViewer example program.}
  2255.         var
  2256.             count: LongInt;
  2257.             anErr: OSErr;
  2258.     begin
  2259.         count := byteCount;
  2260.         repeat
  2261.             if bytesInPictBuffer >= count then begin
  2262.                     BlockMove(curPictBufPtr, dataPtr, count);
  2263.                     curPictBufPtr := Ptr(Ord4(curPictBufPtr) + count);
  2264.                     bytesInPictBuffer := bytesInPictBuffer - count;
  2265.                     count := 0;
  2266.                 end
  2267.             else begin        {Not enough in buffer}
  2268.                     if bytesInPictBuffer > 0 then begin
  2269.                             BlockMove(curPictBufPtr, dataPtr, bytesInPictBuffer);
  2270.                             dataPtr := Ptr(Ord4(dataPtr) + bytesInPictBuffer);
  2271.                             count := count - bytesInPictBuffer;
  2272.                         end;
  2273.                     FillPictBuffer;
  2274.                 end;
  2275.         until count = 0;
  2276.     end;
  2277.  
  2278.  
  2279.     procedure BitInfo (var srcBits: PixMap; var srcRect, dstRect: rect; mode: integer; maskRgn: rgnHandle);
  2280.         var
  2281.             i, size: integer;
  2282.     begin
  2283.         if BitInfoCount = 0 then begin
  2284.                 PictSrcRect := srcRect;
  2285.                 if srcBits.rowBytes < 0 then
  2286.                     with srcBits.pmTable^^ do begin {Make sure it is a PixMap.}
  2287.                             size := ctSize;
  2288.                             if size > 255 then
  2289.                                 size := 255;
  2290.                             if size > 0 then begin
  2291.                                     BitInfoCount := BitInfoCount + 1;
  2292.                                     if not UseExistingLUT then
  2293.                                         with info^ do begin
  2294.                                                 for i := 0 to size do
  2295.                                                     cTable[i].rgb := ctTable[i].rgb;
  2296.                                                 LutMode := ColorLut;
  2297.                                                 SetupPseudocolor;
  2298.                                             end;
  2299.                                 end;
  2300.                         end; {with}
  2301.             end;
  2302.     end;
  2303.  
  2304.  
  2305.     procedure GetLUTFromPict (thePict: PicHandle);
  2306.   {Refer to "Screen Dump FKEY for Color Picts", February 1988 MacTutor.}
  2307.         type
  2308.             myPicData = record
  2309.                     p: Picture;
  2310.                     ID: integer
  2311.                 end;
  2312.             myPicPtr = ^myPicData;
  2313.             myPicHdl = ^myPicPtr;
  2314.         var
  2315.             tempProcs: CQDProcs;
  2316.             SavePort: GrafPtr;
  2317.             err: osErr;
  2318.             TempPort: CGrafPort;
  2319.             limbo: rect;
  2320.             xxscale, yyscale: extended;
  2321.     begin
  2322.         GetPort(SavePort);
  2323.         OpenCPort(@TempPort);
  2324.         SetStdCProcs(tempProcs);
  2325.         tempProcs.bitsProc := BitInfoProc;
  2326.         tempProcs.getPicProc := GetPICTDataProc;
  2327.         PictSrcRect := thePict^^.picFrame;
  2328.         BitInfoCount := 0;
  2329.         TempPort.grafProcs := @tempProcs;
  2330.         err := SetFPos(PictF, fsFromStart, 512 + SizeOf(Picture));
  2331.         FillPictBuffer;
  2332.         limbo := thePict^^.picFrame;
  2333.         OffsetRect(limbo, 10000, 10000);
  2334.         if not PictReadErr then
  2335.             DrawPicture(thePict, limbo);
  2336.         CloseCPort(@TempPort);
  2337.         SetPort(SavePort);
  2338.         with info^, PictSrcRect do begin
  2339.                 LoadLUT(cTable);
  2340.                 xxScale := (right - left) / PixelsPerLine;
  2341.                 yyScale := (bottom - top) / nLines;
  2342.                 if (xxScale > 1.0) and ((PixelsPerLine * xxScale) <= MaxLine) and ((xxScale - yyScale) < 0.1) then begin
  2343.                         PixelsPerLine := right - left;
  2344.                         nLines := bottom - top;
  2345.                     end;
  2346.             end; {with}
  2347.     end;
  2348.  
  2349.  
  2350.     function OpenPict;{(fname:str255; vnum:integer; Reverting:boolean):boolean}
  2351.         var
  2352.             err: OSErr;
  2353.             i: integer;
  2354.             iptr, p: ptr;
  2355.             PictSize, HowBig: LongInt;
  2356.             thePict: PicHandle;
  2357.             tPort: GrafPtr;
  2358.             tempProcs: CQDProcs;
  2359.             SaveProcsPtr: QDProcsPtr;
  2360.             SaveInfo: InfoPtr;
  2361.             SaveGDevice: GDHandle;
  2362.             TiffInfo: TiffInfoRec;
  2363.  
  2364.         procedure Abort;
  2365.         begin
  2366.             if not reverting then begin
  2367.                     DisposePtr(pointer(Info));
  2368.                     Info := SaveInfo;
  2369.                     LoadLUT(info^.cTable);
  2370.                 end;
  2371.             if thePict <> nil then
  2372.                 DisposeHandle(handle(thePict));
  2373.             if PictF <> 0 then
  2374.                 err := fsclose(PictF);
  2375.             {exit(OpenPict);} {ppc-bug}
  2376.         end;
  2377.  
  2378.     begin
  2379.         if BitInfoProc=nil
  2380.             then BitInfoProc:=NewRoutineDescriptor(@BitInfo, uppQDBitsProcInfo, GetCurrentISA);
  2381.         if GetPictDataProc=nil
  2382.             then GetPictDataProc:=NewRoutineDescriptor(@GetPictData, uppQDGetPicProcInfo, GetCurrentISA);
  2383.         PictF := 0;
  2384.         thePict := nil;
  2385.         OpenPict := false;
  2386.         PictReadErr := false;
  2387.         ShowWatch;
  2388.         SaveInfo := Info;
  2389.         err := fsopen(fname, vNum, PictF);
  2390.         if CheckIO(err) <> 0 then begin
  2391.             Abort;
  2392.             exit(OpenPict)
  2393.         end;
  2394.         if not Reverting then begin
  2395.                 iptr := NewPtr(SizeOf(PicInfo));
  2396.                 if iptr = nil then begin
  2397.                         PutMemoryAlert;
  2398.                         err := fsclose(PictF);
  2399.                         exit(OpenPict)
  2400.                     end;
  2401.                 Info := pointer(iptr);
  2402.                 CloneInfo(SaveInfo^, Info^);
  2403.             end;
  2404.         with Info^ do begin
  2405.                 err := GetEof(PictF, PictSize);
  2406.                 if CheckIO(err) <> 0 then begin
  2407.                     Abort;
  2408.                     exit(OpenPict)
  2409.                 end;
  2410.                 PictSize := PictSize - 512;
  2411.                 if PictSize <= 0 then begin
  2412.                     Abort;
  2413.                     exit(OpenPict)
  2414.                 end;
  2415.                 WhatToOpen := OpenPICT2;
  2416.                 if not OpenHeader(PictF, fname, vnum, TiffInfo) then begin
  2417.                     Abort;
  2418.                     exit(OpenPict)
  2419.                 end;
  2420.                 thePict := PicHandle(NewHandle(SizeOf(Picture)));
  2421.                 if thePict = nil then begin
  2422.                     Abort;
  2423.                     exit(OpenPict);
  2424.                 end;
  2425.                 err := SetFPos(PictF, fsFromStart, 512);
  2426.                 if CheckIO(err) <> 0 then begin
  2427.                     Abort;
  2428.                     exit(OpenPict)
  2429.                 end;
  2430.                 howBig := SizeOf(Picture);
  2431.                 err := FSRead(PictF, howBig, Pointer(thePict^));
  2432.                 if CheckIO(err) <> 0 then begin
  2433.                     Abort;
  2434.                     exit(OpenPict)
  2435.                 end;
  2436.                 with thePict^^.PicFrame do begin
  2437.                         nlines := bottom - top;
  2438.                         PixelsPerLine := right - left;
  2439.                     end;
  2440.          {....}
  2441.                 err := GetEof(PictF, howBig);
  2442.                 howBig := howBig - (512 + SizeOf(Picture));
  2443.                 InitPictBuffer(HowBig * 2);
  2444.                 if GetPtrSize(PictBuffer) >= howBig then begin
  2445.                         err := FSRead(PictF, howBig, PictBuffer);
  2446.                         if CheckIO(err) <> NoErr then begin
  2447.                                 DisposeHandle(handle(thePict));
  2448.                                 DisposePtr(PictBuffer);
  2449.                                 err := fsclose(PictF);
  2450.                                 exit(OpenPict)
  2451.                             end;
  2452.                         fitsInPictBuffer := true;
  2453.                     end
  2454.                 else
  2455.                     fitsInPictBuffer := false;
  2456.                 if (LutMode = ColorLut) or (LutMode = CustomGrayscale) or (fileVersion = 0) then
  2457.                     GetLUTFromPict(thePict);
  2458.                 if not Reverting then begin
  2459.                         p := GetImageMemory(SaveInfo);
  2460.                         if p = nil then begin
  2461.                                 DisposeHandle(handle(thePict));
  2462.                                 DisposePtr(PictBuffer);
  2463.                                 err := fsclose(PictF);
  2464.                                 exit(OpenPict)
  2465.                             end;
  2466.                         PicBaseAddr := p;
  2467.                         MakeNewWindow(fname);
  2468.                         if ScreenDepth <> 8 then begin
  2469.                             SelectAll(false);
  2470.                             DoOperation(EraseOp);
  2471.                             changes:= false;
  2472.                             KillRoi;
  2473.                         end;
  2474.                     end;
  2475.                 if (PixMapSize > UndoBufSize) and (not Reverting) then begin
  2476.                         PutWarning;
  2477.                         ShowWatch;
  2478.                     end;
  2479.                 if isGrayScaleLUT then
  2480.                     ResetGrayMap;
  2481.                 SaveGDevice := GetGDevice;
  2482.                 SetGDevice(osGDevice);
  2483.                 GetPort(tPort);
  2484.                 SetPort(GrafPtr(osPort));
  2485.                 pmForeColor(BlackIndex);
  2486.                 pmBackColor(WhiteIndex);
  2487.                 RGBForeColor(BlackRGB);
  2488.                 RGBBackColor(WhiteRGB);
  2489.                 EraseRect(PicRect);
  2490.                 SaveProcsPtr := pointer(osPort^.grafProcs);
  2491.                 SetStdCProcs(tempProcs);
  2492.                 tempProcs.getPicProc := GetPICTDataProc;
  2493.                 osPort^.grafProcs := @TempProcs;
  2494.                 err := SetFPos(PictF, fsFromStart, 512 + SizeOf(Picture));
  2495.                 FillPictBuffer;
  2496.                 if not PictReadErr then
  2497.                     DrawPicture(thePict, PicRect);
  2498.                 osPort^.grafProcs := pointer(SaveProcsPtr);
  2499.                 DisposeHandle(handle(thePict));
  2500.                 DisposePtr(PictBuffer);
  2501.                 pmForeColor(ForegroundIndex);
  2502.                 pmBackColor(BackgroundIndex);
  2503.                 SetPort(tPort);
  2504.                 SetGDevice(SaveGDevice);
  2505.                 vref := vnum;
  2506.                 PictureType := PictFile;
  2507.                 revertable := true;
  2508.             end; {with}
  2509.         err := fsclose(PictF);
  2510.         SetupUndo;
  2511.         if not PictReadErr then
  2512.             OpenPict := true;
  2513.     end;
  2514.  
  2515.  
  2516.     procedure GetCLUT (thePict: PicHandle);
  2517.         type
  2518.             myPicData = record
  2519.                     p: Picture;
  2520.                     ID: integer
  2521.                 end;
  2522.             myPicPtr = ^myPicData;
  2523.             myPicHdl = ^myPicPtr;
  2524.         var
  2525.             tempProcs: CQDProcs;
  2526.             SaveProcsPtr: QDProcsPtr;
  2527.             err: osErr;
  2528.     begin
  2529.         with info^ do begin
  2530.                 SetPort(GrafPtr(osPort));
  2531.                 SaveProcsPtr := pointer(wptr^.grafProcs);
  2532.                 SetStdCProcs(tempProcs);
  2533.                 tempProcs.bitsProc := BitInfoProc;
  2534.                 BitInfoCount := 0;
  2535.                 osPort^.grafProcs := @tempProcs;
  2536.                 DrawPicture(thePict, thePict^^.picFrame);
  2537.                 osPort^.grafProcs := pointer(SaveProcsPtr);
  2538.                 LoadLUT(cTable);
  2539.             end;
  2540.     end;
  2541.  
  2542.  
  2543.     function OpenPICS (name: str255; fRefNum: integer): boolean;
  2544.         var
  2545.             RefNum, picID, hOffset, vOffset, nPICS, i: integer;
  2546.             err: OSErr;
  2547.             PicH: PicHandle;
  2548.             h: handle;
  2549.             MemError, Aborted: boolean;
  2550.             FrameRect: rect;
  2551.             SaveGDevice: GDHandle;
  2552.     begin
  2553.         if BitInfoProc=nil
  2554.             then BitInfoProc:=NewRoutineDescriptor(@BitInfo, uppQDBitsProcInfo, GetCurrentISA);
  2555.         OpenPics := false;
  2556.         if MaxBlock < MinFree then begin
  2557.                 PutError('Insufficient memory to open PICS file.');
  2558.                 exit(OpenPICS);
  2559.             end;
  2560.         ShowWatch;
  2561.         err := SetVol(nil, fRefNum);
  2562.         RefNum := OpenResFile(name);
  2563.         if RefNum = -1 then begin
  2564.                 PutError('Unable to open PICS file.');
  2565.                 exit(OpenPICS);
  2566.             end;
  2567.         nPICS := Count1Resources('PICT');
  2568.         if nPICS < 1 then begin
  2569.                 PutError('No PICTs found.');
  2570.                 CloseResFile(RefNum);
  2571.                 exit(OpenPICS);
  2572.             end;
  2573.         PicH := GetPicture(128);
  2574.         if PicH = nil then begin
  2575.             CloseResFile(RefNum);
  2576.             exit(OpenPICS);
  2577.         end;
  2578.         FrameRect := PicH^^.PicFrame;
  2579.         with FrameRect do begin
  2580.                 hOffset := left;
  2581.                 vOffset := top;
  2582.                 right := right - hOffset;
  2583.                 bottom := bottom - vOffset;
  2584.                 left := 0;
  2585.                 top := 0;
  2586.             end;
  2587.         with FrameRect do
  2588.             if not NewPicWindow(name, right - left, bottom - top) then begin
  2589.                 CloseResFile(RefNum);
  2590.                 exit(OpenPICS);
  2591.             end;
  2592.         with info^ do begin
  2593.                 revertable := false;
  2594.                 StackInfo := StackInfoPtr(NewPtr(SizeOf(StackInfoRec)));
  2595.                 if StackInfo = nil then begin
  2596.                     CloseResFile(RefNum);
  2597.                     exit(OpenPICS);
  2598.                 end;
  2599.                 with StackInfo^ do begin
  2600.                         SliceSpacing := 0.0;
  2601.                         FrameInterval := 0.0;
  2602.                         StackType := VolumeStack;
  2603.                         nSlices := 1;
  2604.                         CurrentSlice := 1;
  2605.                         PicBaseH[1] := PicBaseHandle;
  2606.                     end;
  2607.             end;
  2608.         if not UseExistingLUT then
  2609.             GetCLUT(picH);
  2610.         with info^, Info^.StackInfo^ do begin
  2611.                 SaveGDevice := GetGDevice;
  2612.                 SetGDevice(osGDevice);
  2613.                 SetPort(GrafPtr(osPort));
  2614.                 pmBackColor(WhiteIndex);
  2615.                 EraseRect(PicRect);
  2616.                 DrawPicture(picH, PicRect);
  2617.                 ReleaseResource(handle(PicH));
  2618.                 SetGDevice(SaveGDevice);
  2619.                 UpdatePicWindow;
  2620.                 picID := 129;
  2621.                 MemError := false;
  2622.                 for i := 2 to nPICS do begin
  2623.                         PicH := GetPicture(picID);
  2624.                         if (PicH = nil) or (ResError <> NoErr) then
  2625.                             Leave;
  2626.                         h := GetBigHandle(PixMapSize);
  2627.                         if h = nil then begin
  2628.                                 if PicH <> nil then
  2629.                                     ReleaseResource(handle(picH));
  2630.                                 MemError := true;
  2631.                                 Leave;
  2632.                             end;
  2633.                         nSlices := nSlices + 1;
  2634.                         CurrentSlice := CurrentSlice + 1;
  2635.                         PicBaseH[CurrentSlice] := h;
  2636.                         SelectSlice(CurrentSlice);
  2637.                         FrameRect := PicH^^.PicFrame;
  2638.                         with FrameRect do begin
  2639.                                 right := right - hOffset;
  2640.                                 bottom := bottom - vOffset;
  2641.                                 left := left - hOffset;
  2642.                                 top := top - vOffset;
  2643.                             end;
  2644.                         SetGDevice(osGDevice);
  2645.                         EraseRect(PicRect);
  2646.                         if not EqualRect(FrameRect, PicRect) then
  2647.                             BlockMove(PicBaseH[CurrentSlice - 1]^, PicBaseH[CurrentSlice]^, PixMapSize);
  2648.                         DrawPicture(picH, FrameRect);
  2649.                         ReleaseResource(handle(PicH));
  2650.                         SetGDevice(SaveGDevice);
  2651.                         UpdatePicWindow;
  2652.                         UpdateTitleBar;
  2653.                         Aborted := CommandPeriod;
  2654.                         if Aborted then begin
  2655.                                 beep;
  2656.                                 wait(60);
  2657.                                 Leave;
  2658.                             end;
  2659.                         picID := picID + 1;
  2660.                     end;
  2661.                 CloseResFile(RefNum);
  2662.                 if MemError then
  2663.                     PutError('Not enough memory to open all images in PICS file.');
  2664.                 CurrentSlice := 1;
  2665.                 SelectSlice(CurrentSlice);
  2666.                 PictureType := PicsFile;
  2667.                 Revertable := false;
  2668.                 UpdateTitleBar;
  2669.                 UpdateWindowsMenuItem;
  2670.                 if not MemError and not Aborted then
  2671.                     OpenPICS := true;
  2672.             end; {with}
  2673.     end;
  2674.  
  2675.  
  2676. {$D-}
  2677.  
  2678.     procedure OpenAll (RefNum: integer);
  2679.       {Opens all appropriate files in a folder.    Original version contributed by Ira Rampil.}
  2680.         var
  2681.             OpenedOK: boolean;
  2682.             index,vRefNum: integer;
  2683.             name: Str255;
  2684.             ftype: OSType;
  2685.             err: OSErr;
  2686.             PB: CInfoPBRec;
  2687.             dirID,ProcID:LongInt;
  2688.     begin
  2689.         vRefNum:=0;
  2690.         err:=GetWDInfo(RefNum,vRefNum,dirID,ProcID);
  2691.         if err<>noErr then
  2692.             exit(OpenAll);
  2693.         index := 0;
  2694.         while true do begin
  2695.                 index := index + 1;
  2696.                 with PB do begin
  2697.                         ioCompletion := nil;
  2698.                         ioNamePtr := @name;
  2699.                         ioVRefNum := RefNum;
  2700.                         ioDirID:=DirID;
  2701.                         ioFDirIndex := index;
  2702.                         err := PBGetCatInfoSync(@PB); {ppc-bug}
  2703.                         if err = fnfErr then
  2704.                             exit(OpenAll);
  2705.                         ftype := ioFlFndrInfo.fdType;
  2706.                     end;
  2707.                 if ftype = 'IPIC' then begin
  2708.                         WhatToOpen := OpenImage;
  2709.                         if not OpenFile(name, RefNum) then
  2710.                             exit(OpenAll);
  2711.                     end
  2712.                 else if ftype = 'PICT' then begin
  2713.                         if not OpenPICT(name, RefNum, false) then
  2714.                             exit(OpenAll)
  2715.                     end
  2716.                 else if ftype = 'TIFF' then begin
  2717.                         WhatToOpen := OpenTiff;
  2718.                         if not OpenFile(name, RefNum) then
  2719.                             exit(OpenAll);
  2720.                     end
  2721.                 else if ftype = 'PNTG' then
  2722.                     if not OpenMacPaint(name, RefNum) then
  2723.                         exit(OpenAll);
  2724.                 if CommandPeriod or (nPics>=MaxPics) then begin
  2725.                         beep;
  2726.                         exit(OpenAll);
  2727.                     end;
  2728.             end; {while}
  2729.     end;
  2730.  
  2731.  
  2732.     function OpenDialogHook (item: integer; theDialog: DialogPtr): integer;
  2733.         const
  2734.             OpenAllID = 11;
  2735.             KeepLutID = 12;
  2736.         var
  2737.             i: integer;
  2738.     begin
  2739.         if (item = -1) and UseExistingLUT then
  2740.             SetDlogItem(theDialog, KeepLutID, 1);
  2741.         if item = OpenAllID then begin
  2742.                 OpenAllFiles := not OpenAllFiles;
  2743.                 SetDlogItem(theDialog, OpenAllID, ord(OpenAllFiles));
  2744.             end;
  2745.         if item = KeepLutID then begin
  2746.                 UseExistingLUT := not UseExistingLUT;
  2747.                 SetDlogItem(theDialog, KeepLutID, ord(UseExistingLut));
  2748.             end;
  2749.         OpenDialogHook := item;
  2750.     end;
  2751.  
  2752.  
  2753.     function isTiffFile (fname: str255; RefNum: integer): boolean;
  2754.   {Returns true if the first 16-bit word of the file contains 'MM' or 'II' and the second contains 42.}
  2755.         var
  2756.             f: integer;
  2757.             ByteCount: LongInt;
  2758.             hdr: array[1..512] of integer;
  2759.             err: OSErr;
  2760.     begin
  2761.         err := fsopen(fname, RefNum, f);
  2762.         err := SetFPos(f, fsFromStart, 0);
  2763.         ByteCount := 4;
  2764.         err := fsread(f, ByteCount, @hdr);
  2765.         isTiffFile := ((hdr[1] = $4949) and (hdr[2] = $2A00) or (hdr[1] = $4D4D) and (hdr[2] = $002A));
  2766.         err := fsclose(f);
  2767.     end;
  2768.  
  2769.  
  2770.     function DoOpen (FileName: str255; RefNum: integer): boolean;
  2771.         const
  2772.             MyDialogID = 70;
  2773.         var
  2774.             where: Point;
  2775.             reply: SFReply;
  2776.             b: boolean;
  2777.             TypeList: array[0..11] of OSType;
  2778.             FileType: OSType;
  2779.             OKToContinue: boolean;
  2780.             FinderInfo: FInfo;
  2781.             err: OSErr;
  2782.             mySpec:FSSpec;
  2783.     begin
  2784.         if OpenDHookProc=nil
  2785.             then OpenDHookProc:=NewRoutineDescriptor(@OpenDialogHook, uppDlgHookProcInfo, GetCurrentISA);
  2786.         KillOperation;
  2787.         DisableDensitySlice;
  2788.         OpenAllFiles := false;
  2789.         UseExistingLUT := false;
  2790.         OKToContinue := false;
  2791.         if FileName = '' then begin
  2792.                 where.v := 50;
  2793.                 where.h := 50;
  2794.                 typeList[0] := 'IPIC';
  2795.                 typeList[1] := 'PICT';
  2796.                 typeList[2] := 'TIFF';
  2797.                 typeList[3] := 'ICOL';   {Color Tables}
  2798.                 typeList[4] := 'PX05'; {PixelPaint LUT}
  2799.                 typeList[5] := 'CLUT';  {Klutz LUT}
  2800.                 typeList[6] := 'drwC';  {Canvas LUT}
  2801.                 typeList[7] := 'PNTG';  {MacPaint}
  2802.                 typeList[8] := 'PICS';
  2803.                 typeList[9] := 'Iout';    {Outlines}
  2804.                 typeList[10] := 'TEXT';
  2805.                 typeList[11] := 'MooV';
  2806.                 SFPGetFile(Where, '', nil, 12, @TypeList, OpenDHookProc, reply, MyDialogID, nil);
  2807.                 if reply.good then
  2808.                     with reply do begin
  2809.                             FileName := fname;
  2810.                             FileType := ftype;
  2811.                             RefNum := vRefNum;
  2812.                             DefaultRefNum := RefNum;
  2813.                             DefaultFileName := fname;
  2814.                             OKToContinue := true;
  2815.                         end;
  2816.                 if reply.good and OpenAllFiles then begin
  2817.                         OpenAll(RefNum);
  2818.                         exit(DoOpen);
  2819.                     end;
  2820.             end
  2821.         else begin
  2822.                 err := GetFInfo(FileName, RefNum, FinderInfo);
  2823.                 FileType := FinderInfo.fdType;
  2824.                 OKToContinue := true;
  2825.             end;
  2826.         DoOpen := OKToContinue;
  2827.         if OKToContinue then begin
  2828.                 if FileType = 'IPIC' then begin
  2829.                         WhatToOpen := OpenImage;
  2830.                         b := OpenFile(FileName, RefNum)
  2831.                     end
  2832.                 else if FileType = 'PICT' then begin
  2833.                         b := OpenPICT(FileName, RefNum, false)
  2834.                     end
  2835.                 else if FileType = 'TIFF' then begin
  2836.                         WhatToOpen := OpenTIFF;
  2837.                         b := OpenFile(FileName, RefNum)
  2838.                     end
  2839.                 else if FileType = 'ICOL' then
  2840.                     OpenColorTable(FileName, RefNum)
  2841.                 else if FileType = 'PX05' then
  2842.                     ImportPalette('PX05', FileName, RefNum)
  2843.                 else if FileType = 'CLUT' then
  2844.                     ImportPalette('CLUT', FileName, RefNum)
  2845.                 else if FileType = 'drwC' then
  2846.                     ImportPalette('PX05', FileName, RefNum)
  2847.                 else if FileType = 'PNTG' then
  2848.                     b := OpenMacPaint(FileName, RefNum)
  2849.                 else if FileType = 'PICS' then
  2850.                     b := OpenPICS(FileName, RefNum)
  2851.                 else if FileType = 'Iout' then
  2852.                     OpenOutline(FileName, RefNum)
  2853.                 else if FileType = 'TEXT' then begin
  2854.                         if isTiffFile(FileName, RefNum) and not OptionKeyWasDown then begin
  2855.                                 WhatToOpen := OpenTIFF;
  2856.                                 b := OpenFile(FileName, RefNum)
  2857.                             end
  2858.                         else
  2859.                             b := OpenTextFile(FileName, RefNum)
  2860.                     end
  2861.                 else if FileType = 'MooV' then
  2862.                     b := OpenQuickTime(FileName, RefNum, UseExistingLUT)
  2863.                 else begin
  2864.                         WhatToOpen := OpenUnknown;
  2865.                         b := OpenFile(FileName, RefNum)
  2866.                     end;
  2867.                 info^.ScaleToFitWindow := false;
  2868.                 if macro then
  2869.                     GenerateValues;
  2870.             end;
  2871.     end;
  2872.  
  2873.  
  2874.     procedure ImportAllFiles (RefNum: integer);
  2875.         var
  2876.             OpenedOK: boolean;
  2877.             index, vRefNum: integer;
  2878.             name: Str255;
  2879.             ftype: OSType;
  2880.             err: OSErr;
  2881.             PB: CInfoPBRec;
  2882.             dirID,ProcID:LongInt;
  2883.     begin
  2884.         vRefNum:=0;
  2885.         err:=GetWDInfo(RefNum, vRefNum, dirID, ProcID);
  2886.         if err<>noErr then
  2887.             exit(ImportAllFiles);
  2888.         index := 0;
  2889.         while true do begin
  2890.                 index := index + 1;
  2891.                 with PB do begin
  2892.                         ioCompletion := nil;
  2893.                         ioNamePtr := @name;
  2894.                         ioVRefNum := RefNum;
  2895.                         ioDirID:=dirID;
  2896.                         ioFDirIndex := index;
  2897.                         err := PBGetCatInfoSync(@PB); {ppc-bug}
  2898.                         if err = fnfErr then
  2899.                             exit(ImportAllFiles);
  2900.                         ftype := ioFlFndrInfo.fdType;
  2901.                     end;
  2902.                 if (WhatToOpen = OpenCustom) and (ImportCustomDepth <> EightBits) then begin
  2903.                         if not Import16BitFile(name, RefNum) then
  2904.                             exit(ImportAllFiles);
  2905.                     end
  2906.                 else begin
  2907.                         if not OpenFile(name, RefNum) then
  2908.                             exit(ImportAllFiles);
  2909.                     end;
  2910.                 if CommandPeriod or (nPics>=MaxPics) then begin
  2911.                         beep;
  2912.                         exit(ImportAllFiles);
  2913.                     end;
  2914.             end; {while}
  2915.     end;
  2916.  
  2917.  
  2918.     procedure EditImportParameters;
  2919.         const
  2920.             WidthID = 2;
  2921.             HeightID = 3;
  2922.             OffsetID = 4;
  2923.             SlicesID = 5;
  2924.             FixedID = 6;
  2925.             MinID = 7;
  2926.             MaxID = 8;
  2927.         var
  2928.             mylog: DialogPtr;
  2929.             item, fwidth: integer;
  2930.     begin
  2931.         mylog := GetNewDialog(110, nil, pointer(-1));
  2932.         SetDNum(MyLog, WidthID, ImportCustomWidth);
  2933.         SelectdialogItemText(MyLog, WidthID, 0, 32767);
  2934.         SetDNum(MyLog, HeightID, ImportCustomHeight);
  2935.         SetDNum(MyLog, SlicesID, ImportCustomSlices);
  2936.         SetDNum(MyLog, OffsetID, ImportCustomOffset);
  2937.         SetDlogItem(MyLog, FixedID, ord(not ImportAutoScale));
  2938.         if WhatToImport = ImportText then
  2939.             fwidth := 2
  2940.         else
  2941.             fwidth := 0;
  2942.         SetDReal(MyLog, MinID, ImportMin, fwidth);
  2943.         SetDReal(MyLog, MaxID, ImportMax, fwidth);
  2944.         OutlineButton(MyLog, ok, 16);
  2945.         repeat
  2946.             ModalDialog(nil, item);
  2947.             if item = WidthID then begin
  2948.                     ImportCustomWidth := GetDNum(MyLog, WidthID);
  2949.                     if (ImportCustomWidth < 0) or (ImportCustomWidth > MaxPicSize) then begin
  2950.                             ImportCustomWidth := 512;
  2951.                             SetDNum(MyLog, WidthID, ImportCustomWidth);
  2952.                         end;
  2953.                 end;
  2954.             if item = HeightID then begin
  2955.                     ImportCustomHeight := GetDNum(MyLog, HeightID);
  2956.                     if ImportCustomHeight < 0 then begin
  2957.                             ImportCustomHeight := 512;
  2958.                             SetDNum(MyLog, HeightID, ImportCustomHeight);
  2959.                         end;
  2960.                 end;
  2961.             if item = SlicesID then begin
  2962.                     ImportCustomSlices := GetDNum(MyLog, SlicesID);
  2963.                     if ImportCustomSlices < 0 then begin
  2964.                             ImportCustomSlices := 1;
  2965.                             SetDNum(MyLog, SlicesID, ImportCustomSlices);
  2966.                         end;
  2967.                     if ImportCustomSlices > MaxSlices then begin
  2968.                             ImportCustomSlices := MaxSlices;
  2969.                             SetDNum(MyLog, SlicesID, ImportCustomSlices);
  2970.                         end;
  2971.                 end;
  2972.             if item = OffsetID then begin
  2973.                     ImportCustomOffset := GetDNum(MyLog, OffsetID);
  2974.                     if ImportCustomOffset < 0 then begin
  2975.                             ImportCustomOffset := 0;
  2976.                             SetDNum(MyLog, OffsetID, ImportCustomOffset);
  2977.                         end;
  2978.                 end;
  2979.             if item = FixedID then begin
  2980.                     ImportAutoScale := not ImportAutoScale;
  2981.                     SetDlogItem(mylog, FixedID, ord(not ImportAutoScale));
  2982.                 end;
  2983.             if item = MinID then begin
  2984.                     ImportMin := GetDReal(MyLog, MinID);
  2985.                     ImportAutoScale := false;
  2986.                     SetDlogItem(MyLog, FixedID, 1);
  2987.                 end;
  2988.             if item = MaxID then begin
  2989.                     ImportMax := GetDReal(MyLog, MaxID);
  2990.                     ImportAutoScale := false;
  2991.                     SetDlogItem(MyLog, FixedID, 1);
  2992.                 end;
  2993.         until item = ok;
  2994.         DisposeDialog(mylog);
  2995.     end;
  2996.  
  2997.  
  2998.     function ImportDialogHook (item: integer; myLog: DialogPtr): integer;
  2999.         const
  3000.             TiffID = 11;
  3001.             DicomID = 12;
  3002.             TextID = 13;
  3003.             LutID = 14;
  3004.             CustomID = 15;
  3005.             WidthAndHeightID = 16;
  3006.             OffsetID = 17;
  3007.             EightBitsID = 18;
  3008.             SixteenBitsUnsignedID = 19;
  3009.             SixteenBitsSignedID = 20;
  3010.             SwapBytesID = 21;
  3011.             ImportAllID = 22;
  3012.             EditID = 23;
  3013.             CalibrateID = 24;
  3014.             InvertID = 25;
  3015.  
  3016.         var
  3017.             i: integer;
  3018.  
  3019.         procedure SetRadioButtons1;
  3020.             var
  3021.                 i: integer;
  3022.         begin
  3023.             SetDlogItem(mylog, TiffID, 0);
  3024.             SetDlogItem(mylog, DicomID, 0);    
  3025.             SetDlogItem(mylog, LutID, 0);
  3026.             SetDlogItem(mylog, TextID, 0);
  3027.             SetDlogItem(mylog, CustomID, 0);
  3028.             case WhatToImport of
  3029.                 ImportTiff: 
  3030.                     SetDlogItem(mylog, TiffID, 1);
  3031.                 ImportDicom: 
  3032.                     SetDlogItem(mylog, DicomID, 1);
  3033.                 ImportLUT: 
  3034.                     SetDlogItem(mylog, LutID, 1);
  3035.                 ImportText: 
  3036.                     SetDlogItem(mylog, TextID, 1);
  3037.                 ImportCustom: 
  3038.                     SetDlogItem(mylog, CustomID, 1);
  3039.             end;
  3040.         end;
  3041.  
  3042.         procedure SetRadioButtons2;
  3043.             var
  3044.                 i: integer;
  3045.         begin
  3046.             SetDlogItem(mylog, EightBitsID, 0);
  3047.             SetDlogItem(mylog, SixteenBitsUnsignedID, 0);
  3048.             SetDlogItem(mylog, SixteenBitsSignedID, 0);
  3049.             case ImportCustomDepth of
  3050.                 EightBits: 
  3051.                     SetDlogItem(mylog, EightBitsID, 1);
  3052.                 SixteenBitsUnsigned: 
  3053.                     SetDlogItem(mylog, SixteenBitsUnsignedID, 1);
  3054.                 SixteenBitsSigned: 
  3055.                     SetDlogItem(mylog, SixteenBitsSignedID, 1);
  3056.             end;
  3057.         end;
  3058.  
  3059.         procedure ShowParameters;
  3060.             var
  3061.                 str1, str2, str3: str255;
  3062.         begin
  3063.             NumToString(ImportCustomWidth, str1);
  3064.             NumToString(ImportCustomHeight, str2);
  3065.             NumToString(ImportCustomOffset, str3);
  3066.             ParamText(str1, str2, str3, '');
  3067.         end;
  3068.  
  3069.     begin
  3070.         if item = -1 then begin {Initialize}
  3071.                 SetRadioButtons1;
  3072.                 SetRadioButtons2;
  3073.                 ShowParameters;
  3074.                 SetDlogItem(mylog, SwapBytesID, ord(ImportSwapBytes));
  3075.                 SetDlogItem(mylog, ImportAllID, ord(ImportAll));
  3076.                 SetDlogItem(mylog, InvertID, ord(ImportInvert));
  3077.                 SetDlogItem(mylog, CalibrateID, ord(ImportCalibrate));
  3078.             end;
  3079.         if (item >= TiffID) and (item <= CustomID) then begin
  3080.                 case item of
  3081.                     TiffID: 
  3082.                         WhatToImport := ImportTiff;
  3083.                     DicomID: 
  3084.                         WhatToImport := ImportDicom;    
  3085.                     LutID: 
  3086.                         WhatToImport := ImportLUT;
  3087.                     TextID: 
  3088.                         WhatToImport := ImportText;
  3089.                     CustomID: 
  3090.                         WhatToImport := ImportCustom;
  3091.                 end;
  3092.                 SetRadioButtons1;
  3093.             end;
  3094.         if item = EditID then begin
  3095.                 EditImportParameters;
  3096.                 WhatToImport := ImportCustom;
  3097.                 SetRadioButtons1;
  3098.                 ShowParameters;
  3099.                 SetDlogItem(mylog, CalibrateID, ord(ImportCalibrate));
  3100.             end;
  3101.         if (item >= EightBitsID) and (item <= SixteenBitsSignedID) then begin
  3102.                 case item of
  3103.                     EightBitsID: 
  3104.                         ImportCustomDepth := EightBits;
  3105.                     SixteenBitsUnsignedID: 
  3106.                         ImportCustomDepth := SixteenBitsUnsigned;
  3107.                     SixteenBitsSignedID: 
  3108.                         ImportCustomDepth := SixteenBitsSigned;
  3109.                 end;
  3110.                 SetRadioButtons2;
  3111.                 WhatToImport := ImportCustom;
  3112.                 SetRadioButtons1;
  3113.             end;
  3114.         if item = SwapBytesID then begin
  3115.                 ImportSwapBytes := not ImportSwapBytes;
  3116.                 SetDlogItem(mylog, SwapBytesID, ord(ImportSwapBytes));
  3117.                 WhatToImport := ImportCustom;
  3118.                 SetRadioButtons1;
  3119.             end;
  3120.         if item = ImportAllID then begin
  3121.                 ImportAll := not ImportAll;
  3122.                 SetDlogItem(mylog, ImportAllID, ord(ImportAll));
  3123.             end;
  3124.         if item = InvertID then begin
  3125.                 ImportInvert := not ImportInvert;
  3126.                 SetDlogItem(mylog, InvertID, ord(ImportInvert));
  3127.             end;
  3128.         if item = CalibrateID then begin
  3129.                 ImportCalibrate := not ImportCalibrate;
  3130.                 SetDlogItem(mylog, CalibrateID, ord(ImportCalibrate));
  3131.                 WhatToImport := ImportCustom;
  3132.                 SetRadioButtons1;
  3133.             end;
  3134.         ImportDialogHook := item;
  3135.     end;
  3136.  
  3137.  
  3138.     function ImportFile (FileName: str255; RefNum: integer): boolean;
  3139.         const
  3140.             ImportDialogID = 90;
  3141.         var
  3142.             where: Point;
  3143.             typeList: SFTypeList;
  3144.             reply: SFReply;
  3145.             b, ImportingTIFF, HasColorMap: boolean;
  3146.     begin
  3147.         if ImportDHookProc=nil
  3148.             then ImportDHookProc:=NewRoutineDescriptor(@ImportDialogHook, uppDlgHookProcInfo, GetCurrentISA);
  3149.         ImportFile := true;
  3150.         DisableDensitySlice;
  3151.         if not macro then begin
  3152.             ImportAll := false;
  3153.             if WhatToImport=ImportMCID then
  3154.                 WhatToImport:=ImportTIFF;
  3155.         end;
  3156.         if FileName = '' then begin
  3157.                 where.v := 50;
  3158.                 where.h := 50;
  3159.                 SFPGetFile(Where, '', nil, -1, @typeList, ImportDHookProc, reply, ImportDialogID, nil); 
  3160.                 if not reply.good then begin
  3161.                         ImportFile := false;
  3162.                         exit(ImportFile);
  3163.                     end;
  3164.                 with reply do begin
  3165.                         FileName := fname;
  3166.                         RefNum := vRefNum;
  3167.                         DefaultRefNum := RefNum;
  3168.                         DefaultFileName := fname;
  3169.                     end;
  3170.             end;
  3171.         if isTiffFile(FileName, RefNum) and not macro and not OptionKeyWasDown then
  3172.             WhatToImport := ImportTiff;
  3173.         ImportingTIFF := WhatToImport = ImportTiff;
  3174.         if ImportingTIFF then
  3175.             if not GetTIFFParameters(FileName, RefNum, HasColorMap) then
  3176.                 exit(ImportFile);
  3177.         case WhatToImport of
  3178.             ImportMCID: 
  3179.                 WhatToOpen := OpenImported;
  3180.             ImportCustom:  begin
  3181.                     if (ImportCustomDepth <> EightBits) and (ImportCustomWidth > MaxLine) then begin
  3182.                             PutError(concat('Maximum width of imported 16-bit images is ', long2str(MaxLine), '.'));
  3183.                             exit(ImportFile);
  3184.                         end;
  3185.                     WhatToOpen := OpenCustom;
  3186.                 end;
  3187.             ImportDicom: 
  3188.                begin    
  3189.                     ImportDicomImages(FileName, RefNum, ImportAll, ImportFile);
  3190.                     exit(ImportFile);
  3191.                end
  3192.             ImportLUT:  begin
  3193.                     DoImportLut(FileName, RefNum);
  3194.                     exit(ImportFile);
  3195.                 end;
  3196.             ImportText:  begin
  3197.                     ImportFile := ImportTextFile(FileName, RefNum);
  3198.                     exit(ImportFile);
  3199.                 end;
  3200.             otherwise;
  3201.         end;
  3202.         if ImportAll then
  3203.             ImportAllFiles(RefNum)
  3204.         else if (WhatToOpen = OpenCustom) and (ImportCustomDepth <> EightBits) then
  3205.             b := Import16BitFile(FileName, RefNum)
  3206.         else
  3207.             b := OpenFile(FileName, RefNum);
  3208.         if macro then
  3209.             GenerateValues;
  3210.         if ImportingTIFF then
  3211.             WhatToImport := ImportTiff; {GetTIFFParameters may have changed it to ImportCustom.}
  3212.     end;
  3213.  
  3214.  
  3215.     procedure RevertToSaved;
  3216.         var
  3217.             fname: str255;
  3218.             err, f: integer;
  3219.             ok: boolean;
  3220.             size: LongInt;
  3221.     begin
  3222.         if OpPending then
  3223.             KillRoi;
  3224.         DisableDensitySlice;
  3225.         with Info^ do begin
  3226.                 fname := title;
  3227.                 SetPort(wptr);
  3228.                 if PictureType = PICTFile then begin
  3229.                         ok := OpenPICT(fname, vref, true);
  3230.                         UpdatePicWindow;
  3231.                     end
  3232.                 else begin
  3233.                         ShowWatch;
  3234.                         err := fsopen(fname, vref, f);
  3235.                         ok := true;
  3236.                         if HeaderOffset <> -1 then
  3237.                             ok := OpenImageHeader(f, fname, vref);
  3238.                         if ok then begin
  3239.                                 err := SetFPos(f, fsFromStart, ImageDataOffset);
  3240.                                 size := ImageSize;
  3241.                                 CheckFileSize(f, size, ImageDataOffset);
  3242.                                 if size > 0 then
  3243.                                     err := fsread(f, size, PicBaseAddr);
  3244.                                 if odd(PixelsPerLine) then
  3245.                                     UnpackLines;
  3246.                                 if Info^.InvertedImage then
  3247.                                     InvertPic;
  3248.                                 UpdatePicWindow;
  3249.                             end;
  3250.                         err := fsclose(f);
  3251.                         RoiShowing := false;
  3252.                     end;
  3253.                 OpPending := false;
  3254.                 Changes := false;
  3255.                 UpdateTitleBar;
  3256.             end; {with}
  3257.     end;
  3258.  
  3259.  
  3260.     procedure FindWhatToPrint;
  3261.         var
  3262.             kind: integer;
  3263.             WhichWindow: WindowPtr;
  3264.     begin
  3265.         WhatToPrint := NothingToPrint;
  3266.         WhichWindow := FrontWindow;
  3267.         if WhichWindow = nil then
  3268.             exit(FindWhatToPrint);
  3269.         kind := WindowPeek(WhichWindow)^.WindowKind;
  3270.         if (kind = PicKind) and info^.RoiShowing and measuring then
  3271.             kind := InfoKind;
  3272.         case kind of
  3273.             PicKind: 
  3274.                 if info^.RoiShowing then
  3275.                     WhatToPrint := PrintSelection
  3276.                 else
  3277.                     WhatToPRint := PrintImage;
  3278.             HistoKind: 
  3279.                 WhatToPrint := PrintHistogram;
  3280.             ProfilePlotKind, CalibrationPlotKind: 
  3281.                 WhatToPrint := PrintPlot;
  3282.             InfoKind, ResultsKind: 
  3283.                 if mCount > 0 then
  3284.                     WhatToPrint := PrintMeasurements;
  3285.             TextKind: 
  3286.                 WhatToPrint := PrintText;
  3287.             otherwise
  3288.                 ;
  3289.         end;
  3290.         if (WhatToPrint = NothingToPRint) and (info <> NoInfo) then
  3291.             WhatToPrint := PrintImage;
  3292.     end;
  3293.  
  3294.  
  3295.     procedure CheckRoiBounds;
  3296.     begin
  3297.         with info^, info^.RoiRect do
  3298.             if (left < 0) or (top < 0) or (right > PicRect.right) or (bottom > PicRect.bottom) then
  3299.                 KillRoi;
  3300.     end;
  3301.     
  3302.     
  3303.     procedure UpdateFileMenu;
  3304.         var
  3305.             ShowItems, isSelection, notStack: boolean;
  3306.             i: integer;
  3307.             str, str2: str255;
  3308.     begin
  3309.         with info^ do begin
  3310.                 ShowItems := Info <> NoInfo;
  3311.                 CheckRoiBounds;
  3312.                 isSelection := RoiShowing and (RoiType = RectRoi);
  3313.                 notStack := StackInfo = nil;
  3314.                 if OptionKeyWasDown and (CurrentKind <> TextKind) then begin
  3315.                         SetMenuItemText(FileMenuH, CloseItem, 'Close All…');
  3316.                         SetMenuItemText(FileMenuH, SaveItem, 'Save All');
  3317.                         SetMenuItem(FileMenuH, CloseItem, ShowItems);
  3318.                     end
  3319.                 else begin
  3320.                         SetMenuItemText(FileMenuH, CloseItem, 'Close…');
  3321.                         if isSelection and notStack and (CurrentKind <> TextKind) and (PictureType <> TiffFile) and (PictureType <> PictFile) and (CurrentKind = PicKind) then
  3322.                             SetMenuItemText(FileMenuH, SaveItem, 'Save Selection')
  3323.                         else
  3324.                             SetMenuItemText(FileMenuH, SaveItem, 'Save');
  3325.                         SetMenuItem(FileMenuH, CloseItem, ShowItems or (CurrentKind = TextKind) or (CurrentKind = ResultsKind) or (CurrentKind = ProfilePlotKind) or (CurrentKind = CalibrationPlotKind) or (CurrentKind = HistoKind));
  3326.                     end;
  3327.                 case CurrentKind of
  3328.                     ProfilePlotKind, CalibrationPlotKind: 
  3329.                         ExportAsWhat := asPlotValues;
  3330.                     HistoKind: 
  3331.                         ExportAsWhat := asHistogramValues;
  3332.                     ResultsKind: 
  3333.                         ExportAsWhat := asMeasurements;
  3334.                     PicKind:  begin
  3335.                             if (SaveAsWhat <> asPICT) then
  3336.                                 SaveAsWhat := asTiff;
  3337.                             if (ExportAsWhat > asText) then
  3338.                                 ExportAsWhat := asRaw;
  3339.                         end;
  3340.                     otherwise
  3341.                 end;
  3342.                 if isSelection and notStack and (SaveAsWhat <> AsPalette) and (CurrentKind <> ResultsKind) and (CurrentKind <> TextKind) then
  3343.                     SetMenuItemText(FileMenuH, SaveAsItem, 'Save Selection As…')
  3344.                 else
  3345.                     SetMenuItemText(FileMenuH, SaveAsItem, 'Save As…');
  3346.                 if isSelection and notStack and (ExportAsWhat <= AsText) then
  3347.                     SetMenuItemText(FileMenuH, ExportItem, 'Export Selection As…')
  3348.                 else
  3349.                     SetMenuItemText(FileMenuH, ExportItem, 'Export…');
  3350.                 for i := SaveItem to SaveAsItem do
  3351.                     SetMenuItem(FileMenuH, i, ShowItems or (CurrentKind = TextKind));
  3352.                 SetMenuItem(FileMenuH, ExportItem, (ShowItems or (CurrentKind = ResultsKind)) and (CurrentKind <> TextKind));
  3353.                 if isSelection then
  3354.                     str := 'Duplicate Selection'
  3355.                 else
  3356.                     str := 'Duplicate';
  3357.                 SetMenuItemText(FileMenuH, DuplicateItem, str);
  3358.                 for i := DuplicateItem to GetInfoItem do
  3359.                     SetMenuItem(FileMenuH, i, ShowItems and (CurrentKind <> TextKind));
  3360.                 if DataType <> EightBits then
  3361.                     str := 'Rescale'
  3362.                 else
  3363.                     str := 'Revert to Saved';
  3364.                 SetMenuItemText(FileMenuH, RevertItem, str);
  3365.                 SetMenuItem(FileMenuH, RevertItem, (Revertable or (DataType <> EightBits)) and (CurrentKind <> TextKind));
  3366.                 SetMenuItem(FileMenuH, PlugInExportItem, ShowItems);
  3367.                 FindWhatToPrint;
  3368.                 case WhatToPrint of
  3369.                     NothingToPrint: 
  3370.                         str := '';
  3371.                     PrintImage: 
  3372.                         str := 'Image';
  3373.                     PrintSelection: 
  3374.                         str := 'Selection';
  3375.                     PrintPlot: 
  3376.                         str := 'Plot';
  3377.                     PrintHistogram: 
  3378.                         str := 'Histogram';
  3379.                     PrintMeasurements: 
  3380.                         str := 'Results';
  3381.                     PrintText: 
  3382.                         str := 'Text';
  3383.                 end;
  3384.                 SetMenuItemText(FileMenuH, PrintItem, concat('Print ', str, '…'));
  3385.                 SetMenuItem(FileMenuH, PrintItem, WhatToPrint <> NothingToPrint);
  3386.             end; {with info^}
  3387.     end;
  3388.  
  3389.  
  3390.     procedure SaveAll;
  3391.         var
  3392.             SaveInfo: InfoPtr;
  3393.             i: integer;
  3394.     begin
  3395.         SaveInfo := Info;
  3396.         SaveAsWhat := AsTiff;
  3397.         SaveAllState := SaveAllStage1;
  3398.         for i := 1 to nPics do begin
  3399.                 Info := pointer(WindowPeek(PicWindow[i])^.RefCon);
  3400.                 SaveAs('', 0);
  3401.                 if CommandPeriod or (SaveAllState = NoSaveAll) then
  3402.                     leave;
  3403.             end;
  3404.         Info := SaveInfo;
  3405.         SaveAllState := NoSaveAll;
  3406.     end;
  3407.  
  3408.  
  3409.     function SuggestedExportName: str255;
  3410.         var
  3411.             name: str255;
  3412.     begin
  3413.         name := info^.title;
  3414.         case ExportAsWhat of
  3415.             asRaw, asMCID, asText:  begin
  3416.                     if name = 'Camera' then
  3417.                         name := 'Untitled';
  3418.                     if ExportAsWhat = AsText then
  3419.                         SuggestedExportName := concat(name, ' (Text)')
  3420.                     else
  3421.                         SuggestedExportName := name;
  3422.                 end;
  3423.             AsLUT: 
  3424.                 SuggestedExportName := 'Palette';
  3425.             asMeasurements: 
  3426.                 SuggestedExportName := concat(name, ' (Measurements)');
  3427.             AsPlotValues: 
  3428.                 SuggestedExportName := concat(name, ' (Plot Values)');
  3429.             asHistogramValues: 
  3430.                 SuggestedExportName := concat(name, ' (Histogram)');
  3431.             asCoordinates: 
  3432.                 SuggestedExportName := concat(name, ' (Coordinates)');
  3433.         end;
  3434.     end;
  3435.  
  3436.  
  3437.     function ExportHook (item: integer; theDialog: DialogPtr): integer;
  3438.         const
  3439.             EditTextID = 7;
  3440.             RawID = 9;
  3441.             xyCoordinatesID = 16;
  3442.         var
  3443.             i: integer;
  3444.             fname: str255;
  3445.             NameEdited: boolean;
  3446.     begin
  3447.         if item = -1 then {Initialize}
  3448.             SetDlogItem(theDialog, RawID + ord(ExportAsWhat), 1);
  3449.         fname := GetDString(theDialog, EditTextID);
  3450.         NameEdited := fname <> SuggestedExportName;
  3451.         if (item >= RawID) and (item <= xyCoordinatesID) then begin
  3452.                 ExportAsWhat := ExportAsWhatType(item - RawID);
  3453.                 if not NameEdited then begin
  3454.                         SetDString(theDialog, EditTextID, SuggestedExportName);
  3455.                         SelectdialogItemText(theDialog, EditTextID, 0, 32767);
  3456.                     end;
  3457.                 for i := RawID to xyCoordinatesID do
  3458.                     SetDlogItem(theDialog, i, 0);
  3459.                 SetDlogItem(theDialog, item, 1);
  3460.             end;
  3461.         ExportHook := item;
  3462.     end;
  3463.  
  3464.  
  3465.     procedure Export (name: str255; RefNum: integer);
  3466.         const
  3467.             CustomDialogID = 100;
  3468.         var
  3469.             where: Point;
  3470.             reply: SFReply;
  3471.             isSelection: boolean;
  3472.             kind: integer;
  3473.             SaveAsState: SaveAsWhatType;
  3474.     begin
  3475.         if ExportDHookProc=nil
  3476.             then ExportDHookProc:=NewRoutineDescriptor(@ExportHook, uppDlgHookProcInfo, GetCurrentISA);
  3477.         with info^ do begin
  3478.                 if (name = '') or ((RefNum = 0) and (pos(':', name) = 0)) then begin
  3479.                         where.v := 50;
  3480.                         where.h := 50;
  3481.                         if name = '' then
  3482.                             name := SuggestedExportName;
  3483.                         SFPPutFile(Where, 'Save as?', name, ExportDHookProc, reply, CustomDialogID, nil);
  3484.                         if not reply.good then begin
  3485.                                 AbortMacro;
  3486.                                 exit(Export);
  3487.                             end;
  3488.                         with reply do begin
  3489.                                 name := fname;
  3490.                                 RefNum := vRefNum;
  3491.                                 DefaultRefNum := RefNum;
  3492.                             end;
  3493.                     end;
  3494.                 if (Info = NoInfo) and (ExportAsWhat <= asText) then begin
  3495.                     PutError('No image data available.');
  3496.                     AbortMacro;
  3497.                     exit(Export);
  3498.                 end;
  3499.                 CheckRoiBounds;
  3500.                 isSelection := RoiShowing and (RoiType = RectRoi);
  3501.                 case ExportAsWhat of
  3502.                     asRaw, asMCID:  begin
  3503.                             if ExportAsWhat = asMCID then
  3504.                                 InvertPic;
  3505.                             SaveAsState := SaveAsWhat;
  3506.                             if ExportAsWhat = AsRaw then
  3507.                                 SaveAsWhat := asRawData
  3508.                             else
  3509.                                 SaveAsWhat := SaveAsMCID;
  3510.                             if isSelection then
  3511.                                 SaveSelection(name, RefNum, false)
  3512.                             else
  3513.                                 SaveAsTIFF(name, RefNum, 0, 0, false);
  3514.                             SaveAsWhat := SaveAsState;
  3515.                         end;
  3516.                     AsText: 
  3517.                         ExportAsText(name, RefNum);
  3518.                     AsLUT: 
  3519.                         SaveLUT(name, RefNum);
  3520.                     asMeasurements: 
  3521.                         if mCount > 0 then
  3522.                             ExportMeasurements(name, RefNum)
  3523.                         else
  3524.                             PutError('Sorry, but no measurements are available to export.');
  3525.                     AsPlotValues: 
  3526.                         if PlotWindow <> nil then begin
  3527.                                 kind := WindowPeek(PlotWindow)^.WindowKind;
  3528.                                 case kind of
  3529.                                     ProfilePlotKind: 
  3530.                                         ConvertPlotToText;
  3531.                                     CalibrationPlotKind: 
  3532.                                         ConvertCalibrationCurveToText;
  3533.                                     otherwise
  3534.                                         TextBufSize := 0;
  3535.                                 end;
  3536.                                 SaveAsText(name, RefNum);
  3537.                             end
  3538.                         else
  3539.                             beep;
  3540.                     asHistogramValues: 
  3541.                         if HistoWindow <> nil then begin
  3542.                                 ConvertHistoToText;
  3543.                                 SaveAsText(name, RefNum);
  3544.                             end
  3545.                         else
  3546.                             beep;
  3547.                     asCoordinates: 
  3548.                         ExportCoordinates(name, RefNum);
  3549.                     otherwise
  3550.                         beep;
  3551.                 end; {case}
  3552.                 if (SaveAsWhat = asRawData) and (SaveAllState <> SaveAllStage2) then
  3553.                     SaveAsWhat := asTIFF;
  3554.             end; {with}
  3555.     end;
  3556.  
  3557.  
  3558.  
  3559. end.